next_inactive up previous


Bayonne User Manual

Anders Dahnielson
<anders@mysite.se>

2002-07-10


Contents

General Information About Bayonne

What Is Bayonne

GNU Bayonne, the telecommunications application server of the GNU project, offers a scalable, media independent free software environment for development and deployment of telephony application services for use with current and next generation telephone networks. GNU Bayonne is already commercially used as a fully distributed application server with multi-line telephony cards from many vendors under free operating systems such as GNU/Linux and FreeBSD. GNU Bayonne is typically used to create enhanced carrier services such debit calling as well as to create enterprise applications such as voice mail and customized or web integrated interactive voice response applications.

To speed development and simplify deployment of custom applications, Bayonne offers it's own native script interpreter which may be directly extended thru modular DSO plugins and TGI scripted applications. TGI, "Telephony Gateway Interface", allows Bayonne to be easily integrated with other system resources, such as web servers, databases, and other application servers using standard and familiar tools that are well understood such as Perl, TCL, and Python.

Bayonne can be used today most completely under GNU/Linux with an ever wider selection of telephony hardware. Bayonne has also been built under, and can be used with, FreeBSD and the new Voicetronix API. Bayonne is highly portable and will compile under most multi-threaded POSIX operating systems, including Solaris and Unixware. As Bayonne's telephony hardware and next generation media support broadens, support for functional deployment under operating systems beyond GNU/Linux will continue to increase.

How you can help

There are many ways you can contribute to Bayonne even if you do not code. We need people to help with languages and building of multi-lingual voice libraries, people to help with testing, with documentation, and even with the new web site. If you wish to help Bayonne, feel free to send email to dyfet@gnu.org.

About This Manual

This manual was put together by Anders Dahnielson <anders@mysite.se> and recently revised by David Sugar <dyfet@ostel.com> and Jason Spence <thalakan@ostel.com>. However, most of the text is taken from pre-existing Bayonne documents published separately. This manual is an attempt to unify GNU Bayonne documentation.

History of Bayonne

GNU Bayonne was developed from ACS (Adjunct Communication Server), which had been created as a free telephony server for specialized IVR use in early 2000. ACS was originally started as GPL licensed multi-line voice telephony server, with the goal to be the most flexible and advanced telephony voice messaging server available. Bayonne expanded upon that mission to become a general purpose platform for deploying all forms of voice application services within the GNU project.

The most current release represents milestone #8, and represents the final form of GNU Bayonne for the 1.0 release, scheduled for early July. Between now and July the existing package will be refined and this documentation will be extensively revised.

With Milestone #7 we introduced broad support for high density digital telephony hardware, primarily from Intel/Dialogic and Aculab. With high density digital (PRI) support, it became possible to use GNU Bayonne for various carrier class applications.

Milestone #6 introduced support for XML based scripting. XML support was created by directly transcoding XML content into the Bayonne ccScript virtual execution environment, and then running standard Bayonne applications.

Starting With milestone #5, Bayonne supported FreeBSD in addition to GNU/Linux (and possibly Solaris). 0.5.0 is the first release which demonstrability works under FreeBSD and also happens to support the Voicetronix 4 port analog DSP card which will be used as the core of Bayonne VoIP development in coming weeks. In addition, support for Aculab and Dialogic hardware has been initiated, though it is not yet complete.

The fourth Bayonne milestone featured many changes, starting with international support and the new French language vocabulary. There are many less visible changes that effect and expand the scope of DSO capabilities for the Bayonne server as well as greatly improve stability of the server. With 0.4.2, expanded support for initiating dial-out sessions has been added along with preliminary support for locating streams and the Dialogic SDK.

The 3rd milestone release of Bayonne is being made available from ftp://www.voxilla.org/pub/bayonne immediately. This release represents both a more rigorously tested server, and a "usable" or "deployable" server. An audio library has been recorded for use with the new phrasebook system, and some documentation has been drafted. Many features have also been clarified and greatly expanded upon for better use in deployable servers. A lot of bugs were also found and fixed between 0.2.1 and 0.3.

In particular a number of new issues were identified for both QuickNet and Pika hardware. In the case of QuickNet cards, it was found to be necessary to do a full close/reopen of the /dev/phone devices to reset the card otherwise they stop responding between calls, and this was done in 0.2. When the server is started as root, the /dev/phone devices are initially opened under root, but then the server reduces its privilege to "mail" and can no longer re-open /dev/phone. In 0.3, the server now resets file ownership of /dev/phone devices.

Future of Bayonne

Even before 0.8 was released, work had been started on a second iteration of GNU Bayonne. This second iteration will be used to generate a voice telephony server, an IP ``softswitch application server'', and a dedicated scriptable switch control daemon, all built from a common source base. This development is in current CVS under the module ``BayonneNG'' and will be released as the 2.0 release of Bayonne later this year or early next year.

GNU Bayonne 2.0 already has architectural support for high availability hardware and concepts like de-activating live ports. Support for direct use of switching is also provided for to enable use of applications such as a complete integrated telephone system hosted on free software.

The Name

Some have asked why the package name was changed from ACS to Bayonne. I felt there are several reasons for doing this. First, I have received numerous complaints over the use of the name ACS in that it is similar to Al's Circuit Simulator and several other common packages. Also, I had originally wanted a name that was more than a 3 letter acronym and clearly distinct. Bayonne is taken from the name of the Bayonne "bridge", and represents the idea of this package as a bridge between the computer and telephony worlds. Finally, I wanted to bring across the idea that Bayonne is different than a "1.x" or "2.0" derived release of ACS.

Bayonne Licensing and Support

Licensing Policy

GNU GENERAL PUBLIC LICENSE Version 2, June 1991

Copyright (C) 1989, 1991 Free Software Foundation, Inc. 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed.

Preamble

The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software-to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Library General Public License instead.) You can apply it to your programs, too.

When we speak of free software, we are referring to freedom, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish), that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things.

To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it.

For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights.

We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software.

Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations.

Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that re-distributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all.

The precise terms and conditions for copying, distribution and modification follow.

GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does.

1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program.

You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee.

2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions:

a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change.

b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License.

c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program.

In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License.

3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following:

a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or,

c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable.

If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code.

4. You may not copy, modify, sub-license, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sub-license or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance.

5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it.

6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License.

7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances.

It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice.

This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License.

8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License.

9. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns.

Each version is given a distinguishing version number. If the Program specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation.

10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally.

NO WARRANTY

11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.

END OF TERMS AND CONDITIONS

How to Apply These Terms to Your New Programs

If you develop a new program, and you want it to be of the greatest possible use to the public, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms.

To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found.

<one line to give the program's name and a brief idea of what it does.> Copyright (C) 19yy <name of author>

This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA

Also add information on how to contact you by electronic and paper mail.

If the program is interactive, make it output a short notice like this when it starts in an interactive mode:

Gnomovision version 69, Copyright (C) 19yy name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.

The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items-whatever suits your program.

You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names:

Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.

<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice

This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Library General Public License instead of this License.

Commercial Support

Commercial support and products based on both ACS and Bayonne are already available from several sources.

Open Source Telecom

OST offers commercial support for ACS and Bayonne software deployment, a complete line of turnkey IVR servers based on ACS, and discounts on telephony hardware for use with ACS.

URL: http://www.ostel.com

TekLab

TekLab has offered production support for deployment of ACS solutions since the first widely used releases of ACS.

URL: http://www.teklab.com

MySite Sweden AB

Swedish portal and consulting company that offers custom built solutions deploying Bayonne.

URL: http://www.mysite.se

System Architecture

Introduction

This section provides an overview of the system architecture of a GNU Bayonne server. This overview while useful is not necessary to understand it's operation or successfully deploy services with it. It is meant to help better understand the functionality of Bayonne for those that are interested.

Component Libraries

To create GNU Bayonne we needed a portable foundation written in C++. I wanted to use C++ for several reasons. First, the highly abstract nature of the driver interfaces seemed very natural to use class encapsulation for. Second, I found I personally could write C++ code faster and more bug free than I could write C code.

Why we choose not to use an existing framework is also simple to explain. We knew we needed threading, and socket support, and a few other things. There were no single framework that did all these things except a few that were very large and complex which did far more than we needed. We wanted a small footprint for Bayonne, and the most adaptable framework that we found at the time typically added several megabyte of core image just for the runtime library.

GNU Common C++ (originally APE) was created to provide a very easy to comprehend and portable class abstraction for threads, sockets, semaphores, exceptions, etc. This has since grown into it's own and is now used as a foundation of a number of projects as well as being a part of GNU.

In addition to having portable C++ threading, we needed a scripting engine. This scripting system had to operate in conjunction with a non-blocking state-transition call processing system. It also had to offer immediate call response, and support several hundred to a thousand instances running concurrently in one server image.

Many extension languages assume a separate execution instance (thread or process) for each interpreter instance. These were unsuitable. Many extension languages assume expression parsing with non-deterministic run time. An expression could invoke recursive functions or entire subprograms for example. Again, since we wanted not to have a separate execution instance for each interpreter instance, and have each instance respond to the leading edge of an event call-back from the telephony driver as it steps through a state machine, none of the existing common solutions like TCL, Perl, guile, etc, would immediately work for us. Instead, we created a non-blocking and deterministic scripting engine, GNU ccScript.

GNU ccScript is unique in several ways. It is step executed, and is non-blocking. Statements either execute and return immediately, or they schedule their completion for a later time with the executive. A given "step" is executed, rather than linearly. This allows a single thread to invoke and manage multiple interpreter instances. While GNU Bayonne can support interacting with hundreds of simultaneous telephone callers on high density carrier scale hardware, we do not require hundreds of native "thread" instances running in the server, and we have a very modest CPU load.

Another way GNU ccScript is unique is in support for memory loaded scripts. To avoid delay or blocking while loading scripts, all scripts are loaded and parsed into a virtual machine structure in memory. When we wish to change scripts, a brand new virtual machine instance is created to contain these scripts. Calls currently in progress continue under the old virtual machine and new callers are offered the new virtual machine. When the last old call terminates, the entire old virtual machine is then disposed of. This allows for 100 % uptime even while services are modified.

Finally, GNU ccScript allows direct class extension of the script interpreter. This allows one to easily create a derived dialect specific to a given application, or even specific to a given GNU Bayonne driver, simply by deriving it from the core language through standard C++ class extension.

Class instantiation

Since each vendor of telephony hardware has chosen to create their own unique and substantial application library interface, we needed GNU Bayonne to sit above these and be able to abstract them. Ultimately we choose to create a driver plug-in architecture to do this. What this means is that you can get a card and API from Aculab, for example, write your application in GNU Bayonne using it, and later choose, say, to use Intel telephony hardware, and still have your application run, unmodified. This has never been done in the industry widely because many of these same telephony hardware manufacturers like to produce their own middle-ware solutions that lock users into their products.

To do this, we made Bayonne itself operate as a series of base classes, and then create derived classes which implement functionality as separate plug-in modules with static initialized objects. The server exports it's own symbol map much like a library, and so when the derived plug-in is loaded, the static objects are instantiated, and their constructors are called. These constructors link with and are resolved to base class constructors in the server image which are then automatically invoked and are used to register the plug-in with the server.

The server itself also instantiates some objects at startup even before main() runs. These are typically objects related to plug-in registration or parsing of the configuration file.

Hardware and Drivers

Introduction

GNU Bayonne differs significantly from ACS in the way platform specific telephony API's are integrated. In ACS, a platform specific server must be compiled and installed. In GNU Bayonne, a single (unified) server image is used, and all telephony API's appear as loadable modules. Furthermore, GNU Bayonne differs in that the server can be ran under "user" privilege, at least for most telephony API's, while ACS actually required root permission to execute.

These differences are substantial enough that the very concept of configuration and deployment of GNU Bayonne differs significantly from ACS. This document is not meant to highlight those differences, but to identify issues and configuration options relevant to each driver and telephony vendor that is supported in GNU Bayonne.

This section will provide information on the telephony hardware currently supported by GNU Bayonne and about each of the associated GNU Bayonne plug-in drivers related to that hardware.

Drivers

A "supported" Bayonne telephony device is managed through a plug-in "driver". This "driver" is defined as a shared object module with an extension of ".ivr". Drivers (and other Bayonne "plug-in" resources) are found in /usr/lib/bayonne/version/, such as /usr/lib/bayonne/0.4.4/.

In addition to telephony device "drivers", there are plugins for "integration" services. These typically are used for switch integration, such as the Bayonne "SMDI" module. Other modules offer extended call logging capabilities, network integration, VoIP stacks modified to operate as runtime loadable modules, and script language extensions.

While all other forms of drivers and plugins are optional, Bayonne requires at minimum a telephony device and API "driver" (.ivr) to be selected for Bayonne to execute. Furthermore, at present only one such driver can be selected and made active in any running instance of the Bayonne server.

The primary telephony driver API is selected in the [paths] section of the /etc/bayonne.conf file. The name of the driver to load is specified directly, in the form "driver=drivername", such as "driver=phonedev". A matching "phonedev.ivr" plug-in is then loaded when the Bayonne server is started.

When Bayonne is "configured" (by running ./configure) it will detect what telephony API's have been installed on the host system. If it fails to find the files associated with a given telephony API, then that API will be excluded from Bayonne. If you later add a telephony API, you will need to remove config.cache and then re-run "./configure" before Bayonne will recognize and build drivers for it.

The remaining sections of this document will cover the various driver and plug-in modules currently supported by Bayonne, as well as vendor specific issues.

PHONEDEV.IVR

The phonedev.ivr driver is used to support operating systems such as GNU/Linux which make use of kernel mode "native" telephony drivers commonly found under /dev/phone. This driver supports interaction with kernel telephony "phone" devices through the application of a known set of ioctl calls and the use of "event" notification through the exception bit of the select() call. Phonedev may also support the QuickNet telephony drivers that have been ported to both Solaris and FreeBSD.

The phonedev module does try to treat phone devices in a fully vendor neutral manner. /dev/phone device drivers from different vendors can be loaded and mixed in kernel memory under separate device nodes, and the phonedev.ivr module will accept such a mixed vendor environment as well as query /dev/phone devices for specific features and capabilities that will be supported on each instance in Bayonne.

Furthermore, in that Bayonne executes in "user" mode, the Bayonne server will only open and access "phone" devices that are actually made available to the current user id that Bayonne is running under. This means that if one wants to use, for example, three QuickNet "linejack" cards with Bayonne for servicing incoming calls (say /dev/phone1-4), and yet preserve a QuickNet "phonejack" card for "private" use (say with GnomeMeeting or Speak Freely), then one can simply set the ownership of the linejack cards to match the user id Bayonne will run under, and preserve the phonejack (/dev/phone0) as owned under a different user id (say the user-id of the workstation user who wishes to use Speak Freely).

Finally, the phonedev.ivr can be used in multiple instances of the Bayonne server. Hence, one can run different "application servers" by starting multiple instances of Bayonne under different user id's. Different sets of /dev/phone devices can be marked as owned by each of the expected server user id's, and each server will then operate only with the /dev/phone devices that user id has been granted access to.

One should never start more than one instance of Bayonne under the same effective user id. Also, when using user permissions to partition /dev/phone devices between multiple instances of Bayonne, these device nodes must never be marked with shared group "write" permission, otherwise the device may be accessed under multiple images.

When starting the server under the "root" user, one may find additional problems. Bayonne will change itself from root to a new effective user id once started. Due to a bug in the QuickNet cards, the /dev/phone device must be closed and re-opened between each telephone call. Hence while root, /dev/phone will initially open, but once the server is running /dev/phone devices may no longer work unless they are given r/w access permissions under the effective user id the server is now running under. By default this will be the effective user id of the "mail" account, although it can be changed in [server].

The "phonedev.ivr" uses service threads to service event queues for driving the call processor of each of the open /dev/phone devices. The total number of such devices that will be supported is indicated in the [phone] section of /etc/bayonne using the "devices =" keyword. The default value is currently "16". The maximum value that may be specified is "240". As each device represents an individual telephone line, it is possible some cards may support multiple /dev/phone nodes from a single card. This value thus represents the total "port" capacity that will be tested for rather than the total number of cards that may be supported in a single chassis.

Normally only one or at most two service threads are needed, and these can be selected using the [thread] service = keyword option as described in the bayonne.conf man page. Generally the service threads should run either at or a higher priority than Bayonne itself. The phonedev.ivr can support a maximum of 240 device nodes (sufficient for 10 T-1 spans or 8 E-1 spans), hence, in a very high capacity /dev/phone based SMP server one might wish to select 4 or even 8 service threads.

At the time of this writing, only the QuickNet cards are known to be using /dev/phone drivers under Linux. However, the Voicetronix multi-port analog telephony cards will likely soon also use /dev/phone based Linux kernel modules. It has been assumed a maximum of 16 QuickNet cards can be installed in a single cabinet. It is possible to also have up to 16 Voicetronix cards in a single cabinet, with each card servicing 4 analog telephone lines, for a total capacity of 64 ports.

VPB.IVR

The vpb.ivr driver supports Voicetronix's 4 port analog DSP card. These cards use a ``user mode'' library, libvpb, which must be installed before Bayonne is configured. The old libvpb2 driver is no longer used, and you should delete it from your system to avoid possible compilation problems if you have more than one version of Bayonne installed on your machine. This driver will work for both GNU/Linux and FreeBSD systems. It will work for any target platform that the libvpb library supports in the future.

You can get the Voicetronix driver package at http://www.voicetronix.com.au/.

The vpb.ivr module requires that Bayonne is started under ``root''. This is necessary for Bayonne to access io ports under both the Linux kernel and FreeBSD. Once started, Bayonne will reduce itself to the effective user privilege specified in the [server] section of bayonne.conf.

The [vpb] section of Bayonne must be configured properly before you attempt to start it. If you are using an ISA based Voicetronix card, you must set base address of the ``first'' card (in 0x3x0 range). Bayonne assumes all Voicetronix cards will be in sequential addresses, and hence, if you define the first card as 0x340, and specify two cards, the second card must be set for 0x350.

If you will be using more than one card, you should also set the total number of cards in the system with the ``cards'' variable, as Bayonne cannot currently detect the number of cards in the system.

Multiple instances of Bayonne can be started so long as each instance uses a different set of cards.

A separate service thread is started in Bayonne for each Voicetronix card. This service thread performs all event dispatch and may be tuned for process priority scheduling and by scheduling policy for optimal performance. The current implementation uses the special bayonne mode of the Voicetronix driver, which puts some of the scheduling burden on Bayonne. It is suspected that many things (such as call progress detection and ``pips'') do not work properly in this mode, and users who need those features should try the experimental code which does event dispatching using the normal event mode of the Voicetronix driver.

It is possible to have up to 16 Voicetronix cards in a single PC, for a total capacity of 64 analog telephony ports.

Voicetronix recently released their OpenSwitch12 card, which provides 12 hybrid FXO/FXS ports which are each user-configurable to be either FXS or FXO ports. This card does not currently work under Bayonne, although effort to port the new card to Bayonne is underway.

Note that the Voicetronix cards do not have hardware hangup detection. Hangup detection is currently done via recognition of dialtone, which is almost always played after the telephone company equipment detects remote hangup. However, in certain situations, such as multi-party calls, dialtone will not be played. Be careful to deal with this situation via a timeout or similar workaround if you encounter it when developing your application. Also be careful if you are placing outbound calls and a dialtone occurs during the dialing sequence, as your script will just terminate after hearing the dialtone.

The dialtone detection currently requires 2000 milliseconds of steady dialtone, which may be a bit long for some applications. In particular, outbound dialing currently listens for dialtone for a maximum of 800 milliseconds before deciding there is none and it stops trying to dial out. In those cases, set the ``dialtone'' key in the configuration file to 3500 milliseconds or so.

The Voicetronix API has a software-configurable tone detector which can be set via the VPB_TONE environment variable if your telephone company uses tones the card does not recognize. Consult the Voicetronix documentation in the header of the envtone_read_tone_from_env() function, located in src/envtone.cpp of your Voicetronix library source tree.

Caller ID support is currently broken for some local carriers in the current driver version. Contact Voicetronix for the patch.

Note that systems which do not set the OSTYPE environment variable, (such as newer RedHat distributions and Debian) will fail to compile the Voicetronix library. Set OSTYPE to ``Linux'' in these cases and the library will compile properly. BSD users do not need to worry, as the Makefile defaults to compilation for a BSD system.

DIALOGIC.IVR

Bayonne supports the Dialogic 5.0 runtime release under GNU/Linux distributions based on the 2.2 kernel and Dialogic 5.1 runtime releases under GNU/Linux distributions that use the 2.4 kernel. It may also support Solaris Dialogic runtime, but this has not been tested. To date analog cards, such as the D/41x and EPCI cards work fine. Common digital (T1/E1 PRI) span card support also works for cards that include voice resources. GNU Bayonne auto-detects resources and may support configurations that include separate network termination and voice resource cards, and does support TDM bus operations.

Before you can use Dialogic support, you must install the Dialogic UNIX SDK for your platform. Bayonne is designed "generically" for the standard UNIX SDK, and will work with it under both Solaris and UnixWare, as well as under GNU/Linux. When using GNU/Linux, you must also install the appropriate release of the LiS streams package to match your Dialogic runtime release.

The dialogic.ivr module has been developed to autodetect Dialogic resources at startup. It should detect both analog and digital telephony devices, and will support both with the same ivr driver module, even if both types of devices are mixed on the same system. Currently, Digital support has been tested with classic ISA and PCI T1/E1 span cards using the PRI firmware.

The dialogic.ivr analyses and assigns ALL dialogic devices that it finds at startup. Hence, only one instance of Bayonne may be executed on any given server.

The current implementation does ``static'' assignment of DSP resources at startup, and requires that sufficient vox ports exist for all digital telephony interfaces found in the system. This means one cannot use plain DTI cards unless one has sufficient sc bus voice resource cards also available. This may change in future releases.

PIKA.IVR

Pika dropped support for Linux a while back, and the Bayonne Pika driver has become dormant for the time being. Recently, Pika has announced that they have plans to reinstate Linux support, but it won't be available until at least 2003. Should you wish to use the Pika driver anyway, note that the last release of the Pika MonteCarlo software will only run on a 2.2 series Linux kernel, and you must insert the modules with ``-f'' in order to get them to load properly.

The ``sieze'' handlers are already known to be mispelled. If Pika ever reinstates Linux support, it will be fixed.

VMODEM.IVR

The voicemodem driver does not currently work beyond detecting that a modem is there. Work is being done to support voice modems via the libvoice library included with the mgetty-voice package by Gert Doering and friends.

OH323.IVR

The OpenH323 driver does not currently do much of anything. Jeremy McNamara is currently being sponsored by his fine employer to write it. Contact him for the latest code.

ACULAB.IVR

The aculab driver is now actively used. It is based on the Aculab PRI and BRI span cards with Prosody support. You must install the Aculab call, voice, and switch modules and libraries before building Bayonne Aculab support.

At the moment I assume that root permission is required to access the Aculab, though this may be incorrect.

The aculab module does automatic card timeslot assignment and will detect and allocate aculab timeslot and card resources during startup. In that all devices are allocated at startup, only one instance of Bayonne can be executed on a single server.

A single service thread is maintained for event dispatch, and a service thread is available for each telephone port. This may change later on.

There is an active workgroup working on aculab support, and the mailing list for this can be found at bayonne-aculab@lists.sourceforge.net.

CAPI20.IVR

Current releases of GNU Bayonne support ``CAPI4Linux'' compatible cards that support the CAPI 2.0 api standard. This has been primarily tested using the ``Fritz'' ISDN adapter card which seems popular with European GNU/Linux enthusiasts.

Installing GNU Bayonne (Basics)

How to Get GNU Bayonne

You can download GNU Bayonne directly from ftp://ftp.gnu.org/gnu/bayonne or from any gnu mirror site. You will also need to download and install the GNU Common C++ ``2'' package, and recent releases of GNU ccScript, GNU ccAudio, and GNU ccRTP. All of these are available from the gnu ftp site.

After download you can unpack it with:

tar -zxvf bayonne-{VERSION}.tar.gz

Substitute VERSION with the version of your package. This will unpack the Bayonne distribution in a new directory with the same name as the package.

If you want to retrieve Bayonne from CVS, use the following command sequence:

for i in ccaudio ccrtp ccscript bayonne; do cvs -z3 -d :pserver:anoncvs@subversions.gnu.org:/cvsroot/$i co $i; done

cvs -z3 -d :pserver:anoncvs@subversions.gnu.org:/cvsroot/commoncpp co commoncpp2

Then you can use ``cvs diff'' to create patches if you want to submit patches to the Bayonne mailing list (bayonne-devel@lists.sourceforge.net). Don't forget to run ``cvs update'' before you start each work session!

Supported Operating Systems

With Milestone #8, Bayonne has partial support for Win32 via RedHat's Cygwin layer. No one has been able to get it to compile fully due to a problem with Cygwin's autoconf, but Bayonne will not work even if it did until the driver model is fixed. See the section on driver architecture for details.

A Mac OS X build was tried by Jason Spence on hardware loaned from Apple, but Common C++ does not support the pthread system used on OS X, so the attempts were unsuccessful.

With Milestone #5, Bayonne now supports FreeBSD in addition to GNU/Linux (and possibly Solaris).

Installation Layouts

System Directories

System directories are installed by the distribution of the Bayonne package itself. While they can include application specific files that are placed there later, this is generally not recommended except as noted. Generally Bayonne may be installed in either /usr, or /usr/local. The following examples are based on GNU Bayonne being installed under /usr.

/usr/share/aaprompts{/voice} Bayonne supplied default prompt library. These include phrasebook prompts and anything else found useful to distribute with Bayonne itself. User application voice libraries should never be installed here.
/usr/share/aaprompts/scrname{/voice} Phrase library that is specific to a specified script file. For example, a ``play xx'' command in yy.scr would look for xx.au in /usr/share/aaprompts/yy{/voice}. This allows script files to have their own local voice libraries.
/usr/share/altprompts{/voice} Maybe optionally created for single product turnkey servers. This directory is generally referenced by  prompts, as in "play myprompt".
/usr/share/aascripts Default system scripts supplied with Bayonne. These include test scripts and any simple applications supplied entirely with Bayonne. Turnkey applications may place script files here, though it is not generally recommended except for turnkey product servers.
/usr/share/aawrappers This is a special directory to hold user supplied executables that will be executed thru the bayonne_wrapper program. These programs are generally initiated under the apache user id and converted to the bayonne user id by bayonne_wrapper.
/usr/libexec/bayonne This is the default directory for Bayonne supplied TGI applications. Bayonne distributions will in time add a number of useful tgi libexec files. User supplied TGI applications must also be installed here, as these run under the Bayonne server's user id.
/usr/lib/bayonne/{version}/ This is the install directory for all loadable modules and plugins. There is only one directory, and DSO's are assumed to be compiled against a specific Bayonne version. User created DSO's should be installed here.

VAR Directories

/var/bayonne is used to host all modifiable files, both as distributed with Bayonne, and for user applications. Any reference to a partial path with at least two components will refer to here.

/var/bayonne/tmp A place to record temporary files
/var/bayonne/save A save filespace for serialized classes.
/var/bayonne/prompts Used by the play and record script.
/var/bayonne/maps Used for loadable map files.

HOME Directories

Bayonne itself has a home directory and user id, starting fairly recently. This is typically found as /home/bayonne. A simple "adduser -r bayonne" will create the Bayonne user. The Bayonne server itself runs under the bayonne group when started under root, and tgi executables (and wrappers) will execute with the unprivileged bayonne user id. users may install their own home directories as well. These may be placed under /.bayonne, and can hold a local bayonne script, /.bayonne/bayonnrc, as well as a user's own voice samples, tgi programs, etc. To activate this directory, the user must be added to the ``bayonne'' group in /etc/group.

Individual

/home/bayonne/apps Starting with 0.5.20, this is now the preferred base prefix for installing new Bayonne applications.
/home/bayonne/php A prefix for PHP include and drop files.
/home/bayonne/admin A working directory for plug-in PHP admin forms.
/home/bayonne/html The primary document root for Bayonne integrated web applications. These are typically execute using an Apache server running under the "bayonne" user id rather than the nobody or http user. This is used for applications that include web services like unified messaging. Other kinds of Bayonne apps might integrate with an existing web application by using bayonne_wrappers instead. "Click-to-dial" typically uses wrappers rather than a seperate apache server.

APPS Directories

Starting with 0.5.20, /home/bayonne/apps has become a standard prefix for installing applications. A number of directories exist for this purpose, and a number of special requirements are needed to use this fully.

/home/bayonne/apps/aascripts User supplied application scripts are installed here.
/home/bayonne/apps/{APP}/{%voice} Each application gets it's own private voice library, which is also fully multi-lingual. For a script file to refer to it's APP prompt directory, it must use APP:: notation in play commands. For example, to play the voice mail intro prompt, one might use: "play VMS::intro". This will then play from "/home/bayonne/apps/VMS/UsEngM/intro.au". This allows one to refer to both default prompts supplied in bayonne and application specific prompts installed locally.

User HOME Directories

When starting Bayonne under an ordinary user id, Bayonne will use the local user's home directory rather than /home/bayonne and /var/run, for various things. These are stored under /.bayonne. This has not been changed in awhile, and is only useful if one either always runs bayonne unprivileged, or if one is starting multiple instances for different users.

/.bayonnerc Can be used to override some things found in /etc/bayonne.conf.
/.bayonne{.ctrl,.nodes,.mixers} Local user privileged versions of /var/run files.
/.bayonne/schedule.conf User's private scheduler.
/.bayonne/tgi User's private tgi directory when non-privileged Bayonne is ran.
/.bayonne/aascripts User's private scripts.
/.bayonne/aaprompts/{%voice} User's private "" prompt path. Hence, a play myprompt" should go to here.
/.bayonne/aaprompts/APPS/{%voice} When not running under a privileged user id, the Bayonne application specific working directory will be located in the user's home rather than in /home/bayonne/apps. Hence, a "play myapp::intro" will go to " /.bayonne/aaprompts/myapp/UsEngM/intro.au"

Configuring

The 'configure' shell script attempts to guess correct values for various system-dependent variables used during compilation. It uses those values to create a `Makefile' in each directory of the package. It may also create one or more `.h' files containing system-dependent definitions. Finally, it creates a shell script `config.status' that you can run in the future to recreate the current configuration, a file `config.cache' that saves the results of its tests to speed up reconfiguring, and a file `config.log' containing compiler output (useful mainly for debugging `configure').

Change to the directory where the sources was unpacked and type the following to run 'configure':

./configure

Running `configure' takes awhile. While running, it prints some messages telling which features it is checking for.

By default, Bayonne will attempt to build and install all of the telephony servers supported in the distribution. Since most often only a specific set of servers to support specific vendor telephony hardware you have available are needed, there are ways to select and remove vendor specific server implementations through configure. The advantage of doing this is a shorter compile time and the elimination of distractions from errors in building unneeded API trees.

The ``without-pika'' option removes all Pika Monte Carlo related, modules, and libraries from the build tree. The ``without-phonedev'' option removes all GNU/Linux /dev/phone support.

If you're using `csh' on an old version of System V, you might need to type `sh ./configure' instead to prevent `csh' from trying to execute `configure' itself.

If you need to do unusual things to compile the package, please try to figure out how `configure' could check whether to do them, and mail diffs or instructions to the address given in the `README' so they can be considered for the next release. If at some point `config.cache' contains results you don't want to keep, you may remove or edit it.

Compiling

After you have configured the package you need to compile it. Type the following to to compile the package:

make

To make sure everything went ok. Type the following to run any self-tests that come with the package:

make check

To install the programs and any data files and documentation type:

make install

You can remove the program binaries and object files from the source code directory by typing:

make clean

To also remove the files that `configure' created (so you can compile the package for a different kind of computer), type `make distclean'. There is also a 'make maintainer-clean' target, but that is intended mainly for the package's developers. If you use it, you may have to get all sorts of other programs in order to regenerate files that came with the distribution.

Installing Bayonne (Advanced Topics)

Compilers and Options

Some systems require unusual options for compilation or linking that the `configure' script does not know about. You can give `configure' initial values for variables by setting them in the environment. Using a Bourne-compatible shell, you can do that on the command line like this:

CC=c89 CFLAGS=-O2 LIBS=-lposix ./configure}

Or on systems that have the `env' program, you can do it like this:

env CPPFLAGS=-I/usr/local/include LDFLAGS=-s ./configure

Compiling For Multiple Architectures

You can compile the package for more than one kind of computer at the same time, by placing the object files for each architecture in their own directory. To do this, you must use a version of `make' that supports the `VPATH' variable, such as GNU `make'. `cd' to the directory where you want the object files and executables to go and run the `configure' script. `configure' automatically checks for the source code in the directory that `configure' is in and in `..'.

If you have to use a `make' that does not supports the `VPATH' variable, you have to compile the package for one architecture at a time in the source code directory. After you have installed the package for one architecture, use `make distclean' before reconfiguring for another architecture.

Optional Features

Some packages pay attention to `enable-FEATURE' options to `configure', where FEATURE indicates an optional part of the package. They may also pay attention to `with-PACKAGE' options, where PACKAGE is something like `gnu-as' or `x' (for the X Window System). The `README' should mention any `enable-' and `with-' options that the package recognizes.

For packages that use the X Window System, `configure' can usually find the X include and library files automatically, but if it doesn't, you can use the `configure' options `x-includes=DIR' and `x-libraries=DIR' to specify their locations.

Removing Features

A number of features may be removed from GNU Bayonne at compile time. These options exist to make it possible to create a more custom or compact server such as for deploying a single function embedded telephony server. The following options may be used from configure for this purpose; disable-xml will remove all support for XML scripting, disable-users will remove all support for local user hosted content, and disable-nodes will remove support for the GNU Bayonne multi-node network call model.

Specifying the System Type

There may be some features `configure' can not figure out automatically, but needs to determine by the type of host the package will run on. Usually `configure' can figure that out, but if it prints a message saying it can not guess the host type, give it the `host=TYPE' option. TYPE can either be a short name for the system type, such as `sun4', or a canonical name with three fields:

CPU-COMPANY-SYSTEM

See the file `config.sub' for the possible values of each field. If config.sub' isn't included in this package, then this package doesn't need to know the host type.

If you are building compiler tools for cross-compiling, you can also use the target=TYPE' option to select the type of system they will produce code for and the build=TYPE' option to select the type of system on which you are compiling the package.

Sharing Defaults

If you want to set default values for configure' scripts to share, you can create a site shell script called config.site' that gives default values for variables like CC', cache_file', and prefix'. configure' looks for PREFIX/share/config.site' if it exists, then PREFIX/etc/config.site' if it exists. Or, you can set the CONFIG_SITE' environment variable to the location of the site script. A warning: not all configure' scripts look for a site script.

Operation Controls

configure' recognizes the following options to control how it operates.

cache-file=FILE
Use and save the results of the tests in FILE instead of ./config.cache'. Set FILE to /dev/null' to disable caching, for debugging configure'.

help
Print a summary of the options to configure', and exit.

quiet
silent
-q
Do not print messages saying which checks are being made. To suppress all normal output, redirect it to /dev/null' (any error messages will still be shown).

srcdir=DIR
Look for the package's source code in directory DIR. Usually configure' can determine that directory automatically.

version
Print the version of Autoconf used to generate the configure' script, and exit.

configure' also accepts some other, not widely useful, options.

Networking

Introduction

Bayonne has basic support for a UDP-based Bayonne network protocol which allows Bayonne servers on the same network to discover each other. There currently aren't any tools included in the Bayonne distribution to help you see the network peer table for a given instance of Bayonne, but a developer has written a Java program named ``BayonneMon'' which will listen to the UDP broadcasts and compile a table of the Bayonne instances on your subnet, including port state. You can get the BayonneMon program here:

http://lightconsulting.com/thalakan/code.html

The protocol has two basic types of messages, ``*MON'' packets and ``*BUD'' packets. The MON packets are Bayonne's way of saying ``Hi, I'm here, and here's what I'm doing''. They contain the state of the current ports, the version of Bayonne, and other useful status information.

BUD packets are used as part of the Bayonne buddy election protocol. If Bayonne detects at least one other copy of itself via MON broadcast packets, all copies will initiate the buddy election procedure. This will cause FIXME what? Failover? I don't understand the code.

Protocol

The Bayonne protocol is little more than a dump of the ``statnode_t'' structure. The statnode_t structure has the following fields:

time\_t	update;

The string ``*MON'' or ``*BUD'', indicating the type of packet.

char name[16];

The name of the Bayonne node. This is usually the hostname of the machine, although this can be overridden in bayonne.conf if you, say, had more than one instance of Bayonne running on a machine.

struct in\_addr addr;

FIXME I'm not sure... seems to be used only for BUD packets.

unsigned char version;

The protocol version used. Should be 1 in the endian of the sending machine.

unsigned char buddies;

The number of other Bayonne nodes found so far by the sending node.

unsigned char ports;

The number of DSO ports this instance of Bayonne has running.

char stat[255];

A string indicating the current state of all the DSO ports on the sending instance of Bayonne. Each port gets one character see the source code for your driver to figure out what characters mean which states. For example ``-'' means idle and ``p'' means play for most drivers. Note that only the characters up to the number of the ports on the machine are filled in, the remainder are blank.

If you intend to run Bayonne on a big system with more than 255 ports and want to change the size of this statnode_t member, note that if the packet becomes larger than the UDP MTU for your network medium (1514 for Ethernet), you will have fragmented UDP broadcasts being sent. This shouldn't usually be a problem, but someone had to stick a warning in the manual :)

Troubleshooting

Due to the way that Bayonne loads the Network class (it's instantiated statically at the bottom of network.cpp), it can't catch exceptions thrown by the Socket class if you define a bad address to bind to in bayonne.conf. This will result in the message ``Aborting'' or similar when you try to run Bayonne. To fix it, make sure that you're defining an address that Bayonne really can bind(2) to the address you define in the ``address'' key in your bayonne.conf.

Driver Architecture

Introduction

The Bayonne driver architecture uses a ``plug-in'' style interface to abstract driver-specific details from the ccScript application accessing the hardware. Each plug-in provides state handlers for each call state (ringing, playing audio, conferenced, etc) and possibly an event thread.

Driver Lifecycle

Each driver begins life when plugins.loadDriver() is called from initial() in server.cpp. A configuration lookup is done on the driver key (set in /etc/bayonne.conf) and the path to the .ivr file for the specified driver is calculated. The .ivr file is then loaded via a call to dlopen() (or the equivalent on your system) via Common C++'s DSO class.

All Bayonne drivers have a static instance of their driver class defined at the bottom of driver.cpp. For example, the Voicetronix driver has the following statement at the bottom of its driver.cpp file:

VPBDriver vpbivr;

The VPBDriver class (which represents the driver for all Voicetronix cards in the system) inherits from the Driver class, so a call to the Driver class constructor is triggered when the Voicetronix driver is opened. This is a feature of most UNIX implementations of C++. On those platforms (which are at least BSD and Linux), if at run-time, a shared object containing a static instance of a class is loaded, that class' constructor will be called as well as constructors for any parent classes.

The Driver class constructor is defined as follows:

Driver::Driver() :
aaScript()
{
        active = false;
        if(driver)
                throw(this);

        groups = NULL;
        driver = this;
        status = NULL;

        memset(spans, 0, sizeof(spans));
        memset(cards, 0, sizeof(cards));
}

The ``driver'' variable seen here is of type ``Driver *'' and is a static global variable defined in bayonne.h. After pointing the ``driver'' global pointer to the instance of the driver containined in the driver plug-in, the result is that the rest of the bayone code (mainly in server.cpp) can now access the underlying driver via the abstraction functions defined in class Driver. The two most important functions are start() and stop(), which allow Bayonne to control a driver's active state. There are also several ``get'' functions defined in class Driver which allows Bayonne to interrogate a driver's capabilities and port count. To recap, here's a summary of the driver start-up sequence:

1) The driver DSO is loaded via plugins.loadDrivers().

2) This results in a call to Driver::Driver().

3) This causes the global ``driver'' pointer to point to the newly created instance of the child class driver.

4) The child class driver constructor (e.g. VPBDriver::VPBdriver()) is called. This is where ports actually get initialized and the hardware is prepared to begin receiving calls.

5) Bayonne calls driver->start().

6) This results in a call to the driver-specific start() function, because Driver::start() is declared virtual. In the case of the Voicetronix driver, this is VPBDriver::start(). Any event threads are started up and the hardware begins processing calls.

Win32

One of the reasons why the Win32 build is not going to work for a while is that David Sugar and Jason Spence have determined via a few test cases that it is not possible to link C++ object files into i386 PE DLLs (the format used by DSOs on Win32) unless all of the classes have their parent class constructors symbols resolved in the DLL. That means that the current way of doing things where the Driver class code is in the main Bayonne executable and the driver-specific class code (e.g. VPBDriver) is in a DSO is simply not possible on Win32.

The proposed solution is to create a libbayonne.so and have a simple wrapper program that starts up Bayonne and links in the drivers at run-time. This has not been completed as of yet.

State Handlers

Bayonne, like many telephony applications, uses a state machine to model the behavior of calls. Each port starts out in the ``idle'' state, and changes to other states via Driver::postEvent() (if the current thread is not the thread that will be executing the handler) or by simply setting the global ``handler'' variable for that port (the current thread will be executing it).

Each state's state handler is a function of the name ``Trunk::stateHandler'', where Trunk is the driver's trunk class (DialogicTrunk, VPBTrunk), and ``state'' is replaced with the state name that will be handled. For example, the ring handler for the capi driver is CapiTrunk::ringHandler. The state handlers are handed arguments of type TrunkEvent, which contains the event ID and a union containing data the event handler will need to serve the event (such as digits to be dialed or timeout durations).

Each state handler is initially called with an event type of TRUNK_ENTER_STATE by postEvent, which gives the state handler a chance to set up anything it needs to service other events while in that state. postEvent and the event thread(s) (if any) then continue to call the event handler as events come in and need to be processed. Note that the execution of the state handler (or rather the ``handler'' function pointer defined in the Trunk coass for the driver) is protected by a mutex so that it is not possible to have more than one state handler executing concurrently on a given trunk.

However, state handlers do execute concurrently across trunks. That is, a machine with 4 analog trunks will most likely have four trunk threads going simultaneously, possibly served by a single event thread. The programmer is urged to keep in mind the current thread context whenever dealing with data that could possibly be accessed by several trunks simultaneously, and use mutexes as appropriate to protect the data.

State Handler Reference

Here is the list of states currently present in Bayonne. Note that this list is generated by grepping the source code, so it may not be entirely accurate. Among other things, the dummy driver only has stubs for its states, and the list of ``Comes from'' and ``Goes to'' states is for all drivers. This means that some of the states listed in those lists may not actually call or go to the state they are listed under.

accept
Supported by: dialogic
Comes from: step
Goes to: step Accepts an incoming ISDN call and opens up a timeslot for it. See reject.

answer
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Places the port off-hook.

busy
Supported by: dialogic, dummy, phonedev, pika, vmodem, vpb
Comes from: idle
Goes to: idle
Busies out the port so incoming calls are denied. For analog cards, places the port off-hook. For digital cards, FIXME does what?

collect
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins collecting digits into the digit buffer. When the specified number of digits has been collected or the specified timeout has occured, stops collecting digits and continues executing the script.

detect
Supported by: capi20 (broken), pika (broken)
Comes from: dial, step
Goes to: step
For the Pika driver, handles tone events from the event thread. The reference in the capi20 driver is an anomaly and will be removed.

dial
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: flash, step
Goes to: step
Dials DTMF digits.

duplex
Supported by: capi20, pika
Comes from: step
Goes to: step, exit
Begins recording and playing audio. Its presence in the capi20 driver is an anomaly.

exit
Supported by: pika
Comes from: duplex, play, record
Goes to: play
FIXME: not sure

flash
Supported by: aculab (broken),
Comes from: step
Goes to: step, dial
Does a hookflash.

flashon
Supported by: capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: dial, step, flashoff
Places the port temporarily on-hook to start a hookflash.

flashoff
Supported by: dialogic, dummy, phonedev, pika, vpb
Comes from: flashon
Goes to: dial, step
Places the port back off-hook at the end of a hookflash.

hangup
Supported by: aculab, capi20, dialogic, dummy, oh323, phonedev, pika, rtp, vpb
Comes from: hangup, seize, dial, step
Goes to: idle
Places the port on-hook (analog cards) or shuts down the timeslot (digital cards).

idle
Supported by: all drivers (this is a required state)
Comes from: driver startup, hangup, ring
Goes to: busy, seize, step, release, ring
Stops activity on the port and shuts down any executing script images.

join
Supported by: aculab, capi20, dialogic, pika, vpb
Comes from: step
Goes to: step
Joins two ports together so they can hear and speak to each other. The target port must be in the ``wait'' state.

load
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Loads an XML service. See the section on web services in this manual.

play
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins playing audio from a file.

playwait
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step, play
Waits for the completion of a play service thread.

record
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Begins recording audio to a file.

reject
Supported by: dialogic
Comes from: step
Goes to: step
Rejects an incoming call via the digital signalling channel. See accept.

release
Supported by: dialogic
Comes from: (nowhere)
Goes to: idle
FIXME: Doesn't seem to be called from anywhere in the Dialogic driver.

ring
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vmodem, vpb
Comes from: idle
Goes to: step, idle
Recognizes an incoming ring event and increments the ring counter, then determines whether to start up a script. In some drivers (such as Voicetronix), captures caller ID.

rtp
Supported by: vpb (broken)
Comes from: (broken)
Goes to: (broken)
Connects a call with a RTP stream. Doesn't work right now.

seize
Supported by: dialogic, dummy, phonedev, vmodem, vpb
Comes from: idle
Goes to: step, hangup
Grabs a port in preparation for outbound dialing.

sleep
Supported by: aculab, capi20, dialogic, dummy, phonedev, pika, vpb
Comes from: step
Goes to: step
Waits for a specified duration or number of rings.

step
Supported by: all drivers (this is a required state)
Comes from: all states
Goes to: most states
Executes the next step in the script image and changes the current state if needed. This is probably the most frequently used state.

tone
Supported by: aculab, capi20, dialogic, pika, vpb
Comes from: step
Goes to: step
Generates a tone of user-specified frequency and duration.

wait
Supported by: phonedev, vpb
Comes from: step
Goes to: step, dial
FIXME: I'm not sure what's going on in the phonedev driver, but the vpb driver is placed into the wait state in preparation for a join from another port.

Scripting Language

Introduction

With the Bayonne package a brand new scripting system, ccscript, has been introduced. ccscript differs in a number of fundamental ways from other scripting systems in that it is designed for single-step timed execution from a callback event thread. ccscript is therefore a scripting interpreter that models and controls the behavior of near realtime sequenced state-event engines such as the Bayonne server.

ccscript itself offers a programming model that is easy to embed in C++, that is fully thread safe, and that can be extended thru C++ class inheritance. It also offers extremely low call overhead, and has a two phase compile/memory resident runtime environment. Finally, ccscript allows direct runtime reloading of script images without displacing currently executing scripts.

In the case of Bayonne, we extend ccscript to support telephony functions of the server. The main server offers extensions to the core ccscript language, and each driver can also bind it's own driver specific commands. In some cases plugins other than drivers will also bind extensions to the script interpreter.

When the server is started, or when a new "compile" request is made, the server builds the core memory script image. While runtime replacement will happen in a live Bayonne server, it will only occur when a "compile" request is made thru the fifo interface.

Each script is composed of three parts; an event flag as appropriate, a script command statement, and script command arguments.

Events

The event flag is used to notify where a branch point for a given event occurs while the current script is executing. Events can be receipt of DTMF digits in a menu, a call disconnecting, etc. The script will immediately branch to an event handler designated line when in the "top" part of the script, but will not repeatedly branch from one event handler to another; most event handlers will block while an event handler is active.

The exception to this rule is hangup and error events. These cannot be blocked, and will always execute except from within the event handlers for hangup and/or error themselves. Event handlers can be thought of as being like "soft" signals.

In addition to marking script locations, the script "event mask" for the current line can also be modified. When the event mask is modified, that script statement may be set to ignore or process an event that may occur.

The following event identifiers are considered "standard" for Bayonne:

identifier default description
hangup or êxit detach the calling party has disconnected
^error advance a script error is being reported
^dtmf - any unclaimed dtmf events
^timeout advance timed operation timed out
^0 to 9, a to d - dtmf digits
^pound or star - dtmf "#" or "*" key hit
^tone - tone event heard on line
^busy - busytone heard on line
^signal detach notify while waiting for other trunk
^part or cancel detach conference/join disconnect
^fail or învalid advance failed process
^event - event message received
^child - notify child exiting

Symbol Notation

ccscript recognizes three kinds of symbols; constant "values", %variables, and @indirection. A %variable has content that is alterable. Some %variables are automatically initialized for each and every telephone call, while others may be freely created by scripts themselves.

ccscript also recognizes symbol scope. Local symbols are created within symbol scope, resulting in unique instances within subroutines. In addition, all local symbols in symbol scope are removed when returning from a subroutine. global symbols are visible everywhere under the same instance. A ``global'' symbol uses ``.'' notion, as in %myapp.name, where a ``local'' symbol uses a simple name, as in %name, for example. Generally it is suggested that a given script should organize it's global symbols under a scriptname.xxx format to make it easier to read and understand.

A fourth class of symbol exists only at compile time, $defined symbols are substituted when the script file is compiled, and usually reduce to a simple constant, though variables can be named for the compiler. All constants are defined in the [script] section of bayonne.conf.

You can concatenate symbols and constant strings with either non-quoted whitespace or the comma operator. For example,

set %a ``a'' ``b'', ``c''

results in %a being set to ``abc''.

The following variables are commonly defined:

%session.id id, timeslot, or trunk device number
%script.error last error message
%session.date current date
%session.time current time
%return return value of last libexeced TGI script
%session.gid global call identifier
%session.digits currently collected dtmf digits in the digit buffer
%session.count count of number of digits collected
%session.starttime time of call starting
%session.startdate date of call starting
%session.duration current call duration
%session.callerid identity of calling party
%session.calledid identity of how they called us
%session.home initial script invoked
%session.schedule script that was scheduled
%pstn.dnid did number if available
%pstn.clid ani or caller id number if available
%pstn.name caller name if passed in callerid
%pstn.redirect if origin is a telco redirect
%pstn.ringid if distinctive ringing is available
%pstn.infodigits if telco infodigits were passed to us
%pstn.rings number of rings so far
%policy.name name of policy for this session
%policy.member nth member of this policy
%policy.* various policy variables.
%session.language current language in effect (default = "english")
%session.voice current voice library in effect (default = "UsEngM")
%audio.volume volume level in 0-100 for play and record.
%audio.extension default audio file extension (.au, .wav, etc)
%audio.format default audio format (ulaw, alaw, g721, etc)
%audio.annotation annotation of last played or for recorded file
%audio.played samples played from played file
%audio.recorded samples recorded to record file
%audio.created date played file was created
%audio.timeout timeout in a play wait
%audio.trim minimal number of samples to trim at end of file
%server.ports total ports on bayonne server
%server.version version of bayonne server
%server.software software identifier; "bayonne"
%server.driver which driver we are running
%server.node node id of our server

In addition, DSO based functions will create variables for storing results under the name of the function call, and the DSO lookup module will create a %lookup object to contain lookup results. Also, server initiated scripts can pass and initialize variable arguments.

Basic Commands

There are a number of commands that are part of the core ccscript library itself, and these are documented here.

set %var values...
set var=value ...
set[.min|.max] %var values...
Set a variable to a known value. Can also set multiple variables. Can also set a variable to the minimum or maximum value of a set of values.

clear %var ...
Clear (empty) one or more variables. It does not de-allocate. This means that if you need to determine whether a variable is ``there'' or not in a TGI script which is passed the variable, the empty string is equivalent to a nonexistent variable. For example (using the Perl TGI module):

cleartest.scr:

set %var ``abcdefg''
clear %var
libexec 10 mytgi.pl %somevar

mytgi.pl:

use TGI;
my $var = $TGI::QUERY { 'var' }
if($var eq '' || $var eq '(null)') {
  $var = undef;
}

if(defined $var) {
  # do whatever you need to do...
}

The first if() block in mytgi.pl will be executed because %var is actually passed to the TGI application. However, no value is passed for the variable, which causes the TGI parser to assign the empty string (or the special string ``(null)'' in some cases) to the variable.

init %var values...
init var=value ...
init[.min|.max] %var values...
Initialize a new system variable with default values. If the variable already exists, it is skipped. Optionally multiple variables may be initialized at one. Can also init a variable to a minimum or maximum value of a set of values.

const %var values...
const var=value ...
Set a constant which may not be altered later. Alternately multiple constants may be initialized.

stack[.size] count %var [value ...]
Create a ccScript ``stack'' variable. Stack variables are lifo objects and unwind automatically on reference.

fifo[.size] count %var [value ...]
Create a ccScript fifo ``stack'' variable. This creates a variable that automatically unwinds from first in to last in when referenced.

array[.size] count [values...]
Create a ccScript array composite object.

list[.size] values ...
Create a ccScript array composite with constant values.

sequence[.size] count %var [value ...]
Create a ccScript repeating sequence variable. This repeats content of a sequence in the order set.

cache[.size] count %var [value ...]
Create a ccScript fifo cache variable. This creates a variable that logs and returns content in reverse order.

counter %var
Create a variable that automatically increments as it is referenced.

arm %var
Arm a variable so that it will auto-branch if modified.

disarm %var
Disarm an armed variable.

dup %var %dest
Duplicate an existing object into a new one.

post %var value ...
Post one or more additional values into a stack, fifo, sequence, or cache.

remove %var value ...
Remove a specific value entry from a stack, fifo, sequence, or cache variable.

ref %ref components ...
This can be used by a subroutine to form a local instance of a reference object that points to a real object in the public name space by building a target public object name from components that are then glued with ``.'' notation. This is different from an alias since a simple named alias can only reference the local scope in a subroutine.

alias %name value
Create an alias symbol name that points to a real symbol name when referenced. The alias and target must be in the same scope, hence local aliases cannot reference global objects in subroutines.

size space %var...
Pre-allocate "space" bytes for the following variables.

select value match label [..match-label pairs] [var=val...]
Select is used to branch to a new script based on matching a value or variable to a list of possible values. For each match, a different script or event handler may be selected. Options include "select.prefix" to match string prefixes, "select.suffix" to match by tailing values only, "select.length" to match by length, and "select.value" to match by numeric value. If a branch is found, an optional list of variables can be conditionally set.

inc[.day|.hour|.min|.sec] %timevar [offset]
Increment a variable, perhaps with a specified offset, otherwise by "1". Inc is aware of "time" units and can adjust dates by number of days, or times by hours, minutes, or seconds.

dec[.day|.hour|.min.sec] %timevar [offset]
Decrement a variable, perhaps with a specified offset, otherwise by "1". Dec is aware of "time" unites and can adjust dates by number of days, or times by hours, minutes, or seconds.

goto value [var=value ...]
Goto a named script or event handler in a script. If the goto is successful, an optional list of variables can be conditionally set.

try values... [var=value ...]
Attempt to goto one or more labels. If the label is not found in an existing script, the next one in the list will be tried. If any branch attempt is successful, then optionally variables may also be set.

gosub[.public|.protected] value [var=value ...]
call[.public|.protected] value
Call a named script or event handler as a subroutine. If the call is successful, an optional list of variables can be conditionally set. ``.public'' can be used to specify that the subroutine is ran without a local stack, and ``.protected'' can be used to share the current stack with the subroutine directly rather than having it create a new local context.

load[.get|.post] timeout url [variables]
Invoke a URL thru the plugin XML parser. This internally creates a special  script set. Either the get or post method may be used, and an optional set of variables may be specified for the method.

return [label]
Return from a gosub. You can also return to a specific label or handler within the parent script you are returning to.

pop
Pop a gosub off the stack.

use modulename ...
Load one or more ``.pkg'' ccScript generic shared command extension packages. These are loaded from /usr/lib/ccscript2/modulename.pkg. Modules exist for date and time manipulation, for url string encoding, and file manipulation.

skip [label]
Skip may be used alone to skip over a case statement. This is similar to what c/c++ does with cases if no intervening break is present. Since ccScript automatically behaves as if break is present, skip is needed to flow into another case. The second use of skip is to branch to a local label as defined by the label keyword.

label value ...
Create a named local label to receive a skip command request.

if value op value [and | or ...] label [var=value ...]
Used to test two values or variables against each other and branch when the expression is found true. There are both "string" equity and "value" equity operations, as well as substring tests, etc. Optionally a set of variables can be initialized based on the conditional branch. Multiple conditions may be chained together using either and or or.

if value op value [and | or ...] then [script command]
Used to test two values or variables against each other and execute a single statement if the expression is true. Multiple conditions may be chained together using either and or or.

The valid values for the op argument come in two flavors: ``shell style'' and ``c style''. The two styles for a given type of operator are exactly alike and trigger the same code segment (e.g. both -ne and <> do exactly the same thing). For consistency, it is recommended that only one style is used throughout a given application.

-eq / =
Returns true if the two numeric arguments are equal. Uses atol(3) to convert the two arguments to numbers before comparison. Note that this will result in non-numeric strings being treated as equal when in fact they are not because atol() returns 0 if it cannot convert a string to a number.

-ne / <>
Returns true if the two numeric arguments are not equal. Uses atol(3) to convert the two arguments to numbers before comparison. Note that this will result in non-numeric strings being treated as equal when in fact they are not because atol() returns 0 if it cannot convert a string to a number.

.eq. / ==
Returns true if the two alphanumeric arguments are equal. Uses stricmp(3) to do the comparison. This operator is case-insensitive. Note that older versions of the parser may have problems with the ``=='' version of the operator due to how ccScript used to handle equal signs. If you don't get the expected results, use ``.eq.'' instead.

.ne. / !=
Returns true if the two alphanumeric arguments are equal. This operator is case-insensitive.

$
Returns true if the string given by the left argument is found in the string given by the right argument using strstr(2). This operator is case-sensitive. Example:

	set %a ``Hello''
	set %b ``Hello World!''
	if %a $ %b ::next # returns true

	set %a ``World''
	set %b ``Hello World!''
	if %a $ %b ::next # returns true

	set %a ``hello''
	set %b ``Hello World!''
	if %a $ %b ::next # returns false
	slog ``Could not find string'' # This gets printed

$< / $+
Returns true if the argument on the left is found in the argument on the right using strnicmp(3). If the argument on the left is shorter than the argument on the right, only the first n characters will be compared, where n is the length of the argument on the left. This operator is case-insensitive. Example:

	set %a ``abc''
	set %b ``abc123''
	if %a $< %b ::next # returns true

	set %a ``abcdef''
	set %b ``abc123''
	if %a $< %b ::next # returns false
	

$> / $-
Returns true if the argument on the left is found in the argument on the right using strnicmp(3). If the argument on the left is shorter than the argument on the right, then only the n rightmost characters will be compared, where n is the length of the argument on the left. This operator is case-insensitive. Example:

	set %a ``123''
	set %b ``abc123''
	if %a $> %b ::next # returns true
	
	set %a ``abcdef''
	set %b ``abc123''
	if %a $> %b ::next # returns false
	

-lt / <
Returns true if the numeric argument on the left is less than the numeric argument on the right.

-le / <= / =<
Returns true if the numeric argument on the left is less than or equal to the numeric argument on the right.

-gt / >
Returns true if the numeric argument on the left is greater than the numeric argument on the right.

-ge / >= / =>
Returns true if the numeric argument on the left is greater than or equal to the numeric argument on the right.

if value op value [and | or ...]
then
else
endif
Used to test two values or variables against each other and start a multi-line conditional block. This block is enclosed in a ``then'' line and completed with a ``endif'' line. A ``else'' statement line may exist in between.

for %var values...
Assign %var to a list of values within a loop. A for loop may include case statements.

foreach[.offset] %var %packed
Assign %var from items found in a packed list. An optional offset can be used to skip the first n items. A foreach loop may include case statements.

tryeach[.offset] %packed [var=value ...]
Attempt to branch to a script based on the values held in a packed list. Each item will be tried in term, starting from the offset if one is specified. If a branch point exists an optional list of variables may be conditionally initialized.

do [value op value]
Start of a loop. Can optionally have a conditional test (see if). A do loop may include case statements.

loop [value op value][ and | or ...]
Continuation of a for or do loop. Can optionally have a conditional test (see if).

continue [value op value][ and | or ...]
Continue a loop immediately. Can optionally have a conditional test (see if).

break [value op value][ and | or ...]
Break out of a loop. Can optionally have a conditional test (see if).

case [value op value][ and | or ...]
The case statement is a multiline conditional branch. A single case (or otherwise) line can be entered based on a list of separate case identifiers within a given do or for loop.

slog[.info|.err|.crit|.debug message...
Port a message to the system log as a SYSLOG message. The logging level can be specified as part of the command. If Bayonne or the stand-alone ccScript interpreter are running on a console or under initlog(8), the messages will be output on the standard error descriptor, not standard output. Note that you cannot use % characters in the strings to be outputted.

exit
Terminate script interpreter.

Bayonne Server Commands

The Bayonne server adds a number of additional ccscript commands:

hangup
This is the same as exit, though it can be "trapped" with a hangup handler.

audit[.log|.clear|.post] key1=value1 key2=value2...
Declare or post a CDR record.

import %var ...vars
Import a variable value from "global" name space. Normally each Bayonne trunk has it's own private name space.

export %var ..vars
Export one or more variables into the "global" name space.'

debug message..
Send a message to the debugging monitor.

sleep timeout [rings]
Sleep a specified number of seconds. Can also sleep until the specified number of rings have occurred. Millisecond timeouts may also be specified using ms, as in ``100ms''.

sync timeout [rings]
Wait for a specific number of seconds from the time the call was initiated. This is a time synchronized form of "sleep". A specific number of rings can also be waited for.

pack %var values...
Form comma separated content in a packed %var.

unpack[.offset] %var targets
Unpack a common separated variable object into separate variables. Sometimes operations like "lookup" will return a list of values or data fields.

packed char
Allows one to specify an alternate delimiter for packing and unpacking data fields.

once label
Within a single script, once is guaranteed to only goto a new script (like a goto) "once".

on trap label
Allows one to test for a previously blocked signal and see if it had occurred. If the signal had occurred, then the branch will be taken.

answer [rings [ringtime]]
Answer the line if it has not been answered yet. Optionally wait for a specified number of rings before answering, and allow a maximum inter-ring timeout before considering that ringing has "stopped". If the rings are stopped before the count has been reached, then the call is treated as a hangup (abandon).

collect digits [timeout [term [ignore]]]
Collect up to a specified number of DTMF digits from the user. A interdigit timeout is normally specified. In addition, certain digits can be listed as "terminating" digits (terminate input), and others can be "ignored".

flash offtime ontime
Flash the line a specified number of milliseconds (offtime) and then wait for ontime. If dialtone occurs, then may be used as a branch.

play[.any|.all|.one|.tmp] audiofile(s)
Play one or more audio files in sequence to the user. Bayonne supports raw samples, ".au" samples, and ".wav" files. Different telephony cards support different codecs, so it's best to use ulaw/alaw files if you expect to use them on any Bayonne server. Optionally one can play any of the messages found, or only the first message found, or a temp file which is then erased after play.

record[.append] audiofile [timelimit [abort]]
Record user audio to a file, up to a specified time limit, and support optional abort digits (DTMF). Optionally one can append to an existing file.

dial number [..more digits]
Dial the specified telephone number. A "F" may be used to flash the line, and a "W" to specify a wait for dialtone.

dtmf digits [...more digits]
Generate DTMF digits, like with dial, but do not perform call progress analysis.

transfer number [..more digits]
Dial the specified telephone number and then exit. This is in effect a "blind" transfer/call release, and should use appropriate digits to achieve this effect.

hold
Put a call on hold and release the trunk. Script can be restarted by a hold-recall from the pbx, for example...

map[.prefix|.suffix|.absolute] mapname keyvalue [prefix..]
lookup a key value in a named map table. Optionally strip off a "prefix" from the keyvalue before searching if the prefix value is found. When the key is found in the map table, the specified script is executed with map variables set. Suffix mapping can be used to reduce a route by the reverse order digits.

start[.offset|.group|.wait] [expire] offset|group script [parms]
start a script on another trunk port as offset from the current port %id or by issuing a request against another trunk group. Hence "start 1 test" starts script test on the port next to the current one, for example. Normally, a large offset like "start 24 test" might be used to start a script on the next T span. Start can start a script immediately, or time delayed as a queued request. A ``var=varname'' can be used to save the started session id to a variable.

libexec[.once|.play] timeout program [query-parms]
Execute an external application or system script file thru the Bayonne TGI service. This can be used to run Perl scripts, shell scripts, etc. A timeout specifies how long to wait for the program to complete. A timeout of 0 can be used for starting "detached" commands. Optionally one can set libexec to execute only one instance within a given script, or use .play to run an external tgi that will generate an audio file which will then be played and removed automatically when the tgi exits. IMPORTANT: There is currently a bug that will cause bayonne to segfault inexplicably if you return a TGI variable without a value. Make sure that your TGI script returns a value that takes up a space of one character or more.

speak[.any|.all] phrasebook-rules words...
Used to implement phrasebook rules based prompt generation. See PROMPTS.TXT.

tone tone-name [duration-msec [repeat]]
This can be used to emit tones defined from the bayonne.conf file.

has keyword label
Perform a branch operation if a specified keyword exists (as in a test for a bound module).

missing keyword label
Perform a branch operation if a specified keyword is missing.

schedule name or *
Select alternate scheduling "name" to be in effect or use "*" to clear.

signal trunk [msg]
Send a signal to a trunk in a wait state such as joinable.

idle timeout
Set idle timeout value.

read %var...
read.from script
Read data lines embedded in a script into a set of variables. One can also specify the script to start reading from.

data values...
Embed data for a read statement in a script.

gather %packed member
Gather a packed list of the names of all scripts that contain a specific or named ::member script. This can be used to determine what scripts or apps are present and to generate a menu based on that at runtime.

swap %var1 %var2
Swap two variables.

alias %var %newvar
Alias a variable so that every reference to %var will automatically goto %newvar.

dirname %var
Much like the shell dirname, to extract a directory name from a path.

basename %var [extensions...]
Reduce a variable to a simple base filename, and strip any of the optionally listed extensions from it.

fullpath %var fullpath
If %var is a partial pathname, then merge it with the passed path to form a complete pathname.

insert[.offset|.end] %var values...
This can be used to insert new digit values into a string either at the start, or a specific offset.

delete[.offset|.end] %var patterns...
This is used to strip patterns of digits either from the start or a specific offset in, a digit string. If a given pattern is found, it is removed.

chop[.offset|.end] %var count...
This is used to chop out a specific count of digits from within a string.

trim[.offset|.end] %var count..
This is used to trim leading and trailing digits outside of the range of count and offset specified. It's the inverse of chop.

Optional Commands

Some commands are only implemented by specific drivers. The missing and has functions could be used to test if your driver supports a specific feature or function. The following may exist:

join trunk duration
Join a joinable trunk for a specified duration.

wait duration
Indicate we are joinable for a specified duration.

rtp address portnbr [portbind]
Connect a telephony port to a RTP session directly.

duplex recordfile [playfiles...]
Simultaneous play and record.

enter id
Join a TDM conference resource.

leave
Leave the currently joined conference.

detect timeout
Perform call progress detection for a specified timeout.

Troubleshooting ccScripts and TGIs

The collect command adds to %session.digits, it doesn't overwrite it. Make sure that you're clearing %session.digits before each collect (unless you really do intend to append).

Don't use '=', use '-eq' to check for equality. Also, '==' is broken in older versions of Bayonne. Use '.eq.' instead.

Are you confusing the name of a script (like ``foo'') with a label name (like ``::foo'')?

Remember that the pound sign is used as a comment character. Things like ``dial #'' don't work because ccscript thinks you're starting a comment. Quote the ``#'' character instead.

Make sure you are using the *::foo syntax when playing prompts, and that you have %application.language set properly. ``play foo'' is almost certainly not going to do what it looks like it should do. Use ``play *::foo'' instead.

Make sure that if you use a variable returned by a TGI script that the TGI script defined it. Otherwise bayonne dumps core (as of 0.6.4).

Did the ccscript engine print out any interesting error messages during startup or 'bayctrl compile'? Perhaps you should review them.

Did you remember to run 'bayctrl compile' or to restart bayonne after you modified your script?

If you do things like "goto script", and script.scr looks like this:

::start
do stuff
do stuff 

^event
^event
goto script

The goto will fail. Instead, say "goto script::start".

Make sure that after you deal with an event, the script jumps somewhere. If the path of execution falls off the bottom of the file (or hits another label), then the script engine will jump back to the beginning of the file (or the current label) ad infinitum. Keep in mind that you are developing a telephony application, and you must be constantly interacting with the user or they think you've hung up on them.

When jumping as the result of a conditional (like "if %return -eq 1 goto main"), you don't say ``goto''. State it in the form "if %return -eq 1 main". The goto is implied after the if conditional.

If you're using Perl and it's DBI module for doing database accesses through TGI, here's one way you can retrieve data from the database via fetchall_arrayref(). The syntax seems to be easily forgettable for some reason.

$ref = $sth->fetchall_arrayref();
$row0_col0 = $$ref[0][0];
$row1_col1 = $$ref[1][1];
$row0_col1 = $$ref[0][1];

The standard way to get digits so the caller can interrupt the message is:

clear %session.digits

play *::1 # "Press 1 for foo, press 2 for baz, press 3 for gronk..."
sleep 60

^dtmf
	collect 1 5 "*#" "ABCD"
	if %session.digits -eq 1 ::label1
	if %session.digits -eq 2 ::label2
	goto ::invalid

The standard way to get digits so the caller can't interrupt the message is:

clear %session.digits

play *::1 # "Press 1 for foo, press 2 for baz, press 3 for gronk..."
collect 1 5 "*#" "ABCD"
if %session.digits -eq 1 ::label1
if %session.digits -eq 2 ::label2
goto ::invalid

It's a good idea to document your TGI return values in your program header. Make a template for all your TGI programs and stick to it. Make sure there's a section for the return values in the headers and use it. One convention seen around the OST code is to use 1 for a successful call, 0 for an unsuccessful call, and -1 for an internal script error.

Remember that the value of the %return variable is persistent. If you aren't careful, your TGI scripts will fall through without setting a return value. This is especially annoying if you forget to set a return value which means "operation successful" If you don't see a line like this in the server logs:

fifo: cmd=SET&2&return&1

Then your TGI script isn't setting a return value. The ccscript that's executing your TGI will then use the return value from the last ccscript you executed, which is just hours of debugging fun. Especially when one of your TGIs is working just fine (but doesn't set a return value) and your ccscript checks the return value to see if an error occurred, and guess what, it's the return value from the TGI script you called before the current one. Chances are that that return value doesn't have anything to do with the return value from the TGI script you just executed, which leads to very confusing results.

Document your database schema. Make sure that you put the column indexes into the database schema document, and you include a Big Fat Warning that tells any potential modifiers of said document that if they touch the document, they get to audit any database access code that uses hard-coded column indexes. The idea is that if they change the database schema, those column indexes may no longer be valid. An even better solution (if your TGI language supports it) is to define a set of symbolic constants for the database columns in one file and include the constant definitions in all the database access code.

Phrasebook Rules

Introduction

Bayonne is provided with a standard "prompt" library which supports prompts for letters and numbers as needed by the "phrasebook" rules based phrase parser. The phrasebook uses named rules based on the current language in effect, as held in "%language" in ccscript.

Phrase rules can be placed in bayonne.conf proper under the appropriate language and in application specific conf files as found in /etc/bayonne.d. English "rules" are found under section [english] in the .conf files, for example.

Phrasebook prompts are used to build prompts that are effected by content. Lets take the example of a phrase like "you have ... message(s) waiting". In english this phrase has several possibilities. Depending on the quantity involved, you may wish to use a singular or plural form of message. You may wish to substitute the word "no" for a zero quantity.

In Bayonne phrasebook, we may define this as follows:

in your script command:

	speak &msgswaiting %msgcount no msgwaiting msgswaiting

We would then define under [english] something like:

msgswaiting = youhave &number &zero &singular &plural

This assumes you have the following prompt files defined for your application:

youhave.au "you have"
no.au "no"
msgwaiting.au "message waiting"
msgswaiting.au "messages waiting"

The system will apply the remaining rules based on the content of %msgcount. In this sense, phrasebook defined rules act as a kind of "printf" ruleset. You can also apply rules inline, though they become less generic for multilingual systems. The assumption is that the base rules can be placed in the [...] language area, and that often the same voice prompts can be used for different effect under different target languages.

The speaking of numbers itself is held in the default Bayonne distribution, though the default prompt list can also be replaced with your own. Rules can also appear "within" your statement, though this generally makes them non-flexible for different languages.

Speaking of currency "values" have specific phrasebook rules. Currency values are also subject to the "&zero" rule, so for example:

balance=youhave &cy &zero remaining

and using:

speak &balance %balance nomoney

can use the alternate "no monay" .au prompt rather than saying "0 dollars".

English

The following default phrasebook rules are or will be defined for english:

&number speak a number unless zero
&unit speak a number as units; zero spoken
&order speak a "order", as in 1st, 2nd, 3rd, etc.
&skip skip next word if spoken number was zero.
&ignore always ignore the next word (needed to match multilingual).
&use always use the next word (needed to match multilingual).
&spell spell the word or speak individual digits of a number.
&zero substitute a word if value is zero else skip.
&single substitute word if last number spoken was 1.
&plural substitute word if last number spoken was not 1.
&date speak a date.
&day speak only day of the week of a date.
&weekday speak the current day of the week.
&time speak a time.
&primary speak primary currency value (dollar(s) and cent(s))
&local speak local currency
&duration speak hours, minutes, and seconds, for duration values.
&cy speak default currency (either primary, local, or both)

Number Prompts

0, 1, 2, 3, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 30, 40, 50, 60, 70, 80, 90, hundred, thousand, million, billion, point

Order Prompts

1st, 2nd, 3rd, 4th, 5th, 6th, 7th, 8th, 9th, 10th, 11th, 12th, 13th, 14th, 15th, 16th, 17th, 18th, 19th, 20th, 30th, 40th, 50th, 60th, 70th, 80th, 90th

Date/Time Prompts

sunday, monday, tuesday, wednesday, thursday, friday, saturday
january, february, march, april, may, june, july, august, September, october, november, december
am, pm

Currency Prompts

dollar, dollars, cent, cents, and, or

TGI Services

Introduction

The TGI system used in Bayonne is very similar to the CGI protocol used for integrating dynamic executables with web servers. The primary difference is that where CGI uses environment variables, Bayonne TGI uses standard input and standard output instead.

The TGI equivalent of ``Hello World'' in Perl using the TGI module is:

hello.scr:

answer 2 # pick up the phone
libexec 10 hello.pl
slog %return

hello.pl:

use TGI;
use lib $ENV{'SERVER_LIBEXEC'};
TGI::set(return => 'Hello World!');

This will cause the message 'Hello World!' to be slogged from Bayonne. Here's a more complex example:

hello.scr:

answer 2
set %a 1
set %b 1
libexec 10 adder.pl %a %b
if % return -eq -1 ::error
slog %return # outputs ``2''

::error
play *::999 # ``An error has occured, please see the server error log for details.''
slog ``Something went wrong a couple lines ago.  Bailing out.''
hangup
exit

adder.pl:

use TGI;
use lib $ENV{'SERVER_LIBEXEC'};
my $a = $TGI::QUERY{'a'};
my $b = $TGI::QUERY{'b'};
if(! defined $a || ! defined $b) {
  printf(``Missing either A or B or both.'');
  TGI::set(return => -1);
  exit(1);
}
TGI::set(return => $a + $b);

This should output the number 2. Note the extensive error checking.

TGI Errors

Telephony applications are very unlike other computer applications in that they need to be more ``fail-soft'' than a traditional windowed application. In other words, only very serious errors such as an inability to contact a database server or a critical transaction failure should prevent the user from continuing with the telephone call. If a possible error really isn't that serious and it's possible to continue with the phone call even if it occurs, make sure to insert a comment noting that fact in your code.

The rule of thumb for handling TGI errors is: hanging up on users without telling them why is just plain rude. Don't do it. Make sure that you have consistency in your error handlers and that you always play a speech message indicating that something went wrong before hanging up. It's a good idea to have the generic error message include an instruction for the caller to ``call the people who are hosting the application with the current time'' as that will help them search the error logs for the output that occurred during the failed call.

Return Values

Your TGI script passes return values in the TGI variable ``return''. For example, using the TGI.pm Perl module, you would write:

use TGI.pm;
use lib $ENV{'SERVER_LIBEXEC'};

TGI::set(return => 0); # 0 is the return value 
exit(0);

Variables set with the TGI::set method become accessible in the calling ccScript via the ccScript variable of the same name. In this example, the %return variable will be set to 0. These return values can be numbers or characters. You can return as many or as few variables as you want, but it's typical for an application to return a numeric error code in the %return variable so that error checking code after libexecs is more consistent.

Wrapper

Introduction

So, you want to integrate Bayonne with the Web? There are numerous reasons for wanting to do this. Perhaps you are building a unified messaging server with Bayonne, or are trying to build a "click to dial" front end for a Bayonne call agent server or as a compliment to online customer service. While on the surface these may sound similar, they actually are not at all in operation or implementation.

Using Bayonne with an existing site

Starting with 0.5.15, a new Bayonne executable, the "wrapper", was introduced. This is typically used to bridge between a web server, typically running under user id "nobody" or "http", and a Bayonne server, typically running under user id "bayonne". The wrapper (bayonne_wrapper) acts as a simple "sudo" facility, where you specify which scripts the bayonne wrapper will be permitted to execute based on the original requestors "user id".

This is done in the [wrappers] section of Bayonne.conf. Basically one enters the user id and a list of permitted scripts. This list of permitted scripts always execute from /usr(/local)/share/bayonne/aawrappers. Bayonne_wrapper itself runs as a setuid executable, and the scripts or shell commands found in aawrappers are given the user id of the Bayonne server. These scripts also receive useful information in their environment space that is similar to "TGI", but without port specific information.

In particular, a wrapper initiated image receives the server software and version information (BAYONNE_SOFTWARE, BAYONNE_PROTOCOL, BAYONNE_PLATFORM), the token separator to use for fifo control (BAYONNE_TOKEN), the Bayonne node id (BAYONNE_NODE), and the location of the Bayonne fifo and control files (BAYONNE_CONTROL). In addition, the defined trunk group policies are passed as "BAYONNE_POLICIES". No "PORT_xxx" symbols are passed since the wrapper script is not necessarily executing on behalf of a specific and dedicated port resource.

NOTE: These symbols were originally named "SERVER_" in bayonne_wrapper, but were changed to "BAYONNE_" starting with 0.5.17 to avoid conflicts with CGI initiated scripts.

A web server or any other application can use wrapper to invoke executables in aawrappers that manipulate the Bayonne server in a controlled and secure fashion. A wrapper can be invoked thru a CGI and then receive both the web server's CGI state information, and the Bayonne symbol set. A CGI executed wrapper of course can send html back thru stdout to form a web page for the user.

Starting with "0.5.17", Bayonne wrappers can also be used to execute scripts that require interpreters in a fairly direct fashion. For example, if we have a "webdial.cgi" script written in Perl, you will be able to specify as the first line of your script file:

#!/usr/bin/bayonne_wrapper -perl

This will re-execute the script with the Perl interpreter under the specified user id of Bayonne. Similarly, one can then use -bash for /bin/bash, and others for other common shells and interpreters. This provides a simple and direct means to integrate cgi operation with a Bayonne server. In fact, one could use the alias map of apache or other web servers to map the aawrappers directory under a "/bayonne" url as a convenient means to access commonly used wrappers in this way, and in the future some scripts will be provided in the default distribution of Bayonne for this purpose.

Running Bayonne separate from your web server

When you have an existing site, you may not wish to run web servers on Bayonne themselves. You might have a e-commerce "site" you wish to add Bayonne to provide some service, but this need not mean that you install Bayonne on your web server farm, or that Bayonne need even run a publically accessible web server of it's own that has seperate or additional security issues.

Bayonne_wrappers support the use of "ssh" to invoke a bayonne wrapper application on a Bayonne server from a remote machine. This is done by placing a truncated /etc/bayonne.conf file which indicates the node name of the Bayonne server it should contact, and the wrapper permissions to use. The "bayonne_wrapper" will assume to automatically use ssh if the /usr/share/aawrappers directory is not found on the local machine.

On the remote (web server) machine, you will need to create a bayonne "user id". This user id should contain a .ssh/config "entry" with the same name as the Bayonne "node" id in the local /etc/bayonne.conf file, and should list the hostname to actually contact.

You will also need a passwordless ssh key to use between the Bayonne server and the web server. This will allow the bayonne_wrapper to automatically hop between the machines.

The bayonne_wrapper can be symlinked or placed in the web server's cgi directory under the name you will execute the program in "aawrapper" on the Bayonne server under. Hence, you would take bayonne_wrapper, call it for example "webdial.cgi", and place it on the cgi directory of your web server. Since there is no local aawrappers directory, it will initiate a ssh to the Bayonne box and then execute the "real" webdial.cgi from the aawrappers directory there.

SSH does not automatically preserve environment state variables. While bayonne_wrapper has supported ssh for awhile, it is only with 0.5.17 and above does it now preserves key CGI environment variables when it hops between the local and remote machine.

More on running web services on a Bayonne server

While wrappers do allow one to execute Bayonne in conjunction with a web server, this is not necessarily the most efficient manner to do this. A higher demand application might suffer from the performance hit of executing cgi. However, there is one other option currently available.

Certainly one can execute and access Bayonne resources directly if one places a web server on a machine running Bayonne and then has it execute under the same user id that Bayonne does. This allows one to use one of the various highly efficient "mod_xxx" interpreters (like mod_php or mod_perl) to build a web integrated Bayonne service rather than requiring cgi wrappers everywhere.

Incidentally, Bayonne can of course alternately be executed under the same user id as the web server. Which one to change probably depends on your actual need. You can of course also run multiple web server daemons, and have one of them execute under Bayonne's user id.

XML-RPC and other future services

In the future we are looking at using XMLRPC. XMLRPC would eliminate the use of ssh and the difference in operations between a local web cgi or server application invoking services on a locally resident copy of Bayonne vs a copy running on a remote server.

GNU Bayonne ``2'' already includes an integrated http server which will be used to serve both XML encoded system management content and provide support for remote XMLRPC invocation. This interface uses authenticated http headers and can be used to integrate GNU Bayonne with web services directly.

For the desktop user, and to telephony enable desktop applications, like pop-up screens when calls come in, or dialing names from an address book, TOSI will be used, and Bayonne will offer a TOSI server for desktop applications to access using the TOSI interface library definition. I do not know if TOSI will also ever be used for the purposes of Web integration, but it is not impossible. GNU Bayonne ``2'' also supports a TCP command monitor which can be used to remotely access and control a running GNU Bayonne server.

About this document ...

Bayonne User Manual

This document was generated using the LaTeX2HTML translator Version 2002 (1.62)

Copyright © 1993, 1994, 1995, 1996, Nikos Drakos, Computer Based Learning Unit, University of Leeds.
Copyright © 1997, 1998, 1999, Ross Moore, Mathematics Department, Macquarie University, Sydney.

The command line arguments were:
latex2html -nosubdir -split 0 manual.tex

The translation was initiated by David Sugar on 2002-10-05


next_inactive up previous
David Sugar 2002-10-05