====== Asterisk ====== I've been playing with telephones since I was a small child, and I haven't stopped yet. These days I get paid for doing it. Nearly all the telephones I play with now use the SIP protocol, and I've been running a number of Asterisk servers for several years, partly because it enables me to be available on several different numbers (which are 'based' in several different countries) no matter where I am at the time. Asterisk-based systems can be nicely scalable, provided you respect what Asterisk is good at, and what it isn't good at, and substitute appropriate components in the latter cases (FreeSwitch and Kamailio being good examples). Asterisk is good as a switching platform (dialplan, call routing) and as a SIP server (for phones to register to) - it's not so good as a SIP client (for registering to SIP servers). FreeSwitch is better for that. Use the right tool for the job. ===== Dialling using SIP credentials ===== Asterisk can play the rĂ´le of a SIP client (ie: like a telephone) and communicate to another SIP server (maybe Asterisk, maybe not), and it can either REGISTER in order to receive incoming calls, or it can send INVITEs to place outgoing calls (or both). REGISTER needs to be in sip.conf (or the database equivalent), and most documentation will tell you that you need to create a peer in sip.conf in order to be able to send INVITEs. However, this is not always convenient. For example, I have a requirement to create a context which can be called using AMI Originate, passing SIP credentials in as variables, and then to place a call through an arbitrary server using those credentials (the purpose in my case being to verify that someone has given me working credentials before I go ahead and configure them on a production platform). Finding out how to use the Dial() command with SIP credentials is not easy, so here's how you do it: Set(CALLERID(num)=${SIPuser}) Dial(SIP/${SIPdial}:${SIPpass}::${SIPuser}@${SIPhost}) That will place a call to **SIPdial** via **SIPhost**, authenticating as user **SIPuser** with password **SIPpass**. Note that [[http://lists.digium.com/pipermail/asterisk-users/2020-October/295417.html|a bug in Asterisk]] (confirmed in ver 13.14.1 and 16.2.1) means that this command will fail if there is a ! character anywhere in the dial string (the most likely place being the password). I hope this helps someone out there spend less time than I did trying to work out how to do this. ===== Weird lack of error messages ===== Sometimes you can get Asterisk into a state where it doesn't even acknowledge that a perfectly standard command even exists, for example:CLI> sip show peers No such command 'sip show peers' (type 'core show help sip show' for other possible commands) One of the easiest ways to do this is to have a #include macro in a configuration file somewhere, referencing a file which doesn't exist. The standard/etc/init.d/asterisk restartwon't even tell you there's a problem, never mind what the problem is - you have to do a careful search of the log files in /var/log/asterisk to find out what it thinks is wrong. ===== Asterisk Extension Language ===== AEL is a way of writing Asterisk dialplans in a more sensible language. However, it has very [[https://wiki.asterisk.org/wiki/pages/viewpage.action?pageId=4620445|rudimentary documentation]], so here are some of my own notes on how to use it. The syntax and [[https://wiki.asterisk.org/wiki/display/AST/AEL+Keywords|keywords]] of AEL are defined in [[https://wiki.asterisk.org/wiki/display/AST/AEL+version+2+BNF|BNF]], and there are some example pages of the [[https://wiki.asterisk.org/wiki/display/AST/AEL+Example+Usages|commands]]. AEL can be regarded as a meta-language for writing Asterisk dialplans, because you can write them in a way that looks like a normal programming language (including block structures), and the result then gets compiled into the standard Asterisk dialplan language (with numbered lines, and GOTO statements everywhere, looking, as the Asterisk language always does, like BASIC from the 1970s. If you issue the command **dialplan show** Asterisk will show you what your AEL has been compiled into, not the original AEL. There's also a useful tool **aelparse** which will take your AEL dialplan and tell you whether it has syntax errors etc., and if not, can output the compiled version (ie: 1970s BASIC) into a file for you. This allows you to check AEL dialplans without having to load them into Asterisk. I came to AEL after many many years of writing standard Asterisk dialplans (and in fact only discovered it some time after I had given serious thought to what would effectively have been creating AEL myself). Once I decided that I would like to use it, this meant converting my old dialplans into AEL, so to deal with much of the tedium for this I wrote {{:technotes:ael.dialplan.sh|a Bash script}} which does a lot (but not all) of the work for you. ==== Neat things which AEL adds to dialplans ==== You can use the following constructs in AEL dialplans, which are nowhere near as neat and tidy to create in standard Asterisk language: * **if** () ... **else** ... * but no elif :( * **switch** () **case** ... **default:** * including **break** * **for** (a; b; c) ... * including **break** and **continue** * **while** () ... * including **break** and **continue** * **/*** ... ***/** * multi-line comments (including containing **%%//%%** single-line comments) The **return**() statement can also be used anywhere (not just in a subroutine or macro) and goes to the end of the macro or context. ==== Caveats ==== AEL (and its documentation) is far from perfect. * For one thing, as soon as you start using any of the above constrcutions in your dialplans, AEL will liberally pepper the output with things like "NoOp(Finish if_switch_SwitchTest_5410)" which means the phrases (which you didn't put into the original dialplan) likely end up in your log files too (depending on your chosen verbosity of logging). * The [[https://wiki.asterisk.org/wiki/display/AST/AEL+Conditionals|documentation]] for the "switch" statement states that "Neither the switch nor case values are wrapped in $[ ]; they can be constants, or ${var} type references only." * However variables can **only** be global variables - standard ones simply don't work. * Simple assignments such as "a=42" may seem nicer and more in keeping with other languages than "Set(a=42)" but you need to be **very** aware that the right-hand side of all such assignments get automatically wrapped in "$[ ... ]", meaning that any arithmetic symbols such as + - * / which exist inside the **values** of any variables __will__ get evaluated and may give you a surprise. ---- [[.:|Go up]]\\ Return to [[:|main index]].