Sunday, September 20, 2009

Automatic Asterisk Extensions For Skype Callers

One of the more challenging things about using Asterisk with Skype is the fact that most Asterisk endpoints (phones, ATAs, etc.) don't let you easily dial Skype names. I've come up with a partial solution to this using func_odbc, a Skype alias table and some basic caller-id manipulation. Here's the scoop:

First, create a table in your favorite ODBC-compatible database. Here's my setup for Postgres 8.0. If you're using MySQL the SQL will be slightly different.
--
-- Name: skype_alias; Type: TABLE; Schema: public; Owner: ssokol; Tablespace:
--

CREATE TABLE skype_alias (
id integer NOT NULL,
name character varying(50) NOT NULL,
description character varying(50),
date_added timestamp with time zone DEFAULT now() NOT NULL,
date_updated timestamp with time zone DEFAULT now() NOT NULL,
exten integer NOT NULL
);

--
-- Name: skype_alias_id_seq; Type: SEQUENCE; Schema: public; Owner: ssokol
--

CREATE SEQUENCE skype_alias_id_seq
INCREMENT BY 1
NO MAXVALUE
NO MINVALUE
CACHE 1;

ALTER TABLE public.skype_alias_id_seq OWNER TO ssokol;

--
-- Name: skype_alias_id_seq; Type: SEQUENCE OWNED BY; Schema: public; Owner: ssokol
--

ALTER SEQUENCE skype_alias_id_seq OWNED BY skype_alias.id;


--
-- Name: id; Type: DEFAULT; Schema: public; Owner: ssokol
--

ALTER TABLE skype_alias ALTER COLUMN id SET DEFAULT nextval('skype_alias_id_seq'::regclass);

--
-- Name: skype_alias_name_key; Type: CONSTRAINT; Schema: public; Owner: ssokol; Tablespace:
--

ALTER TABLE ONLY skype_alias
ADD CONSTRAINT skype_alias_name_key UNIQUE (name);

--
-- Name: skype_alias_pkey; Type: CONSTRAINT; Schema: public; Owner: ssokol; Tablespace:
--

ALTER TABLE ONLY skype_alias
ADD CONSTRAINT skype_alias_pkey PRIMARY KEY (id);

Now that the database is built, you need to connect it with the ODBC by creating a 'dsn' (short for Data Source Name) in the /etc/odbc.ini. Here's an approximation of mine:

[asterisk]
Description = Asterisk Database
Driver = PostgreSQL
Trace = Yes
TraceFile = sql.log
Database = asterisk
Servername = localhost
UserName = ssokol
Password = whatever
Port = 5432
Protocol = 6.4
ReadOnly = No
RowVersioning = No
ShowSystemTables = No
ShowOidColumn = No
FakeOidIndex = No
ConnSettings =


Next, you will need to make Asterisk aware of the DSN by adding it to the res_odbc.conf file:

[asterisk]
enabled => yes
dsn => asterisk
username => ssokol
password => whatever
pre-connect => yes


Now Asterisk knows how to talk to the database over ODBC. Next, you need to build a couple of query functions in the func_odbc.ini file:

[SKYPEALIAS]
dsn=asterisk
readsql=SELECT exten FROM skype_alias WHERE name = '${SQL_ESC(${ARG1})}'
writesql=INSERT INTO skype_alias(name, description, exten) VALUES ('${SQL_ESC(${VAL1})}', '${SQL_ESC(${VAL2})}', ${SQL_ESC(${VAL3})})

[SKYPENEXT]
dsn=asterisk
readsql=SELECT MAX(exten) AS maxexten FROM skype_alias;

[SKYPENAME]
dsn=asterisk
readsql=SELECT name FROM skype_alias WHERE exten = ${SQL_ESC(${ARG1})}


These do the following:

The "skypealias" query has both a read and a write function. The read function attempts to return an alias extension number based on a known Skype name. This is executed whenever an incoming Skype call arrives at the Asterisk system.

The write function creates an alias record for the Skype user based on three inputs: Skype name, description (usually the caller-id name value), and the assigned alias extension number.

The "skypenext" query is used to help the system generate a new alias extension number by selecting the current highest value from the skype_alias table. (Note that this could also be done using a sequence, and probably should in Postgres. I'm not sure how sequences work in MySQL, so I'm taking the easy way out here. Feel free to post a comment with the recipe.)

The "skypename" query is used by the system to translate alias numbers into Skype names for outgoing calls.

Once you have the queries set up in func_odbc.conf, you need to add a number of Dialplan macros to your extensions.conf file. These implement the necessary reads and writes:

;Skype Alias - Find or generate an alias extension number for an
;incoming Skype call
[macro-skypealias]

exten => s,1,NoOp(Searching for Skype Extension Alias for ${CALLERID(number)})
exten => s,n,Set(SKYPEXT=${ODBC_SKYPEALIAS(${CALLERID(number)})})
exten => s,n,GotoIf($["${SKYPEXT}" = ""]?create:assign)

exten => s,n(create),Set(SKYPEXT=${ODBC_SKYPENEXT()})
exten => s,n,GotoIf($["${SKYPEXT}" = ""]?noval:nextval)
exten => s,n(noval),Set(SKYPEXT=3000)
exten => s,n(nextval),Set(SKYPEXT=$[${SKYPEXT}+1])
exten => s,n,Set(ODBC_SKYPEALIAS()=${CALLERID(number)},${CALLERID(name)},${SKYPEXT})

exten => s,n(assign),Set(CALLERID(number)=${SKYPEXT})
exten => s,n,MacroExit()

;Translate an alias extension into a Skype name for call-back
[macro-skypename]

exten => s,1,Set(SKYPENAME=${ODBC_SKYPENAME(${ARG1})})


The first macro, "macro-skypealias" needs to be called on all incoming Skype calls. It grabs the Skype name of the caller (which is stored in the caller-id number field in Asterisk) and uses that to search the alias table for an existing number asignment. If it doesn't find one it creates a new alias extension number and stores it in the database. In either case it replaces the caller-id number values with a dial-able value which is passed on to the endpoint.

In this example I've set the Skype alias extensions to start with 3000 (actually 3001) and count up. This is arbitrary and you can alter it to match your dial plan as needed. If you have a LOT of friends on Skype you may want to consider using a four digit extension pattern.

My system has a bunch of Skype names associated with it (remember, with Skype For Asterisk you don't pay for users, you pay for concurrent calls) so I've added a call to the macro for each:

[from_skype]
exten => ssokol.macbook,1,Macro(skypealias)
exten => ssokol.macbook,n,Dial(SIP/ssokol-ip650, 20)
exten => ssokol.macbook,n,Answer()
exten => ssokol.macbook,n,Wait(0.5)
exten => ssokol.macbook,n,Playback(try-my-cell-number)
exten => ssokol.macbook,n,Hangup()

exten => s,1,Macro(skypealias)
exten => s,n,Goto(mainmenu|s|1)


So when a call comes in from Skype, the system automatically generates an alias extension which I can use to call back over Skype from my Polycom IP650 desk phone (or any other normal phone with a key-pad). To make this work, I've included a context that matches Skype alias extensions (in my case 3XXX):

[to_skype]
exten => _3XXX,1,Macro(skypename,${ARG1})
exten => _3XXX,n,Dial(Skype/ssokol.macbook@${SKYPENAME}, 60)
exten => _3XXX,n,Congestion()


I simply include the "to_skype" context along with "inside", "local", "longdistance", "international" and all of my other system contexts. When I dial a 3XXX number Asterisk check the database and tries to translate that into a Skype name to dial. Obviously I could get much fancier in the error handling but this serves as a perfectly worthy example.

Other enhancements that could be added would include a web-based GUI that allows you to manually create alias extensions for people you want to call. Since the alias table is stored in a "real" database (rather than the Asterisk internal Berkley database), it's trivial to hook up a web page for adds, edits and deletes.

Please set this up and give it a try. If you have questions, please post comments.

Monday, August 17, 2009

Gliffy - A Cool SaaS Drawing Tool

Over the past few weeks I've used a Flash-based online tool called Gliffy to create some application diagrams and I'm really quite impressed. Gliffy's been around for a couple of years but it recently got a major upgrade. I would now say that it's passed the "cool thing to try" stage and has reached the point of being a full-on replacement for desktop diagram tools. Keep in mind that my requirements are fairly minimal and your mileage may vary. I need to create basic flowcharts, network diagrams, and the occasional object model, and for that Gliffy does just fine.

It imports/exports in any number of formats including SVG, which can be imported by Visio. It has a pretty good catalog of basic shapes and network elements. It allows you to upload graphics to embed in your drawings. Best of all, its available anywhere and works equally well on Mac, Windows and Linux (at least on my Linux -- again YMMV).

The service has a free option that allows you to store a limited number of private diagrams and an unlimited number of public drawings. For about $5/month you can create a personal account and keep all of your diagrams private. A corporate option lets companies create and share content for a bit less per account (but with a minimum number of accounts).

Saturday, August 15, 2009

Linux Desktop - Finally Ready For Prime Time

Ok, I've been a Linux fan for along time, but always as a server. Very early on I tried to use it as a desktop operating system and found myself spending more time working on Linux than on my actual work. The other day I installed Fedora 11 on my 2nd generation MacBook Pro and discovered, much to my delight, that all of the things that used to be horridly hard have finally been made easy.

First, it just worked. No glitches with the X windows system, no problems getting the wireless to work, no cursing at Bluetooth or raging at the complexity of getting my Verizon EVDO card working. It all just worked.

Big shocker -- its also become much prettier than I ever hoped. The interface still isn't as laden with eye candy as OS X, but it is so much better than what I remember from the early days. The icons are attractive, the color schemes are coordinated and the fonts are smooth and anti-aliased.

I don't know if the experience will be as positive for everyone as it was for me, but if you've previously thought of the Linux desktop as the province of geeks and mad scientists, give it another chance. You can find virtually every application you might want, you can run a virtualized Windows session if you need, and you simply can't beat the price.

Wednesday, April 22, 2009

SpinVox Create: Speech-To-Text Rocks

I've been playing with SpinVox Create, the new open API for the SpinVox speech-to-text (STT) service, and it is wicked cool. Take any recording (well, any short recording), convert it to a uLaw encoded wave file. post it to the API and within roughly four minutes you have the text. It's not always dead on ('Digium' became 'Dig-em!') but the transcription is really very good.

I've built a rough but fairly feature complete Asterisk-to-SpinVox integration in Python. I hope to release it to the public shortly. My goal is to completely displace voicemail. Instead of having a 'voicemail box' your voicemail will become simply another sub-type of your email. Messages will arrive with the text pre-transcribed but with the audio file available if you need to review. My initial cut isn't ready for use in Google Voice but its working and it takes something like 3 lines of dialplan to implement.

Check back soon for a link to the article, full review and the Python source.

Wednesday, October 15, 2008

There Is No Linux

Or at least there is no "Linux Operating System". What can be definitively identified as "Linux" is the kernel, which is only one part of an operating system. An operating system has many other parts and from what I can tell there's not even an attempt at consensus between the various packagers of Linux distributions.

My biggest gripe: I can't ask our engineering department to produce "an install for Linux". There ain't no such thing. There's RPM which RedHat and related distributions use. Debian and its children use .deb files. And even that doesn't accurately summarize the issue. Each sub-variation has its own structure and constituent components so they each need their own version of the .rpm or .deb file.

But wait, that's not all. Linux packages are nearly always dependent on other Linux packages, so when you go to install an RPM for one package there's a really good chance it will fail with a message that your system is missing some dependency. So you download and try to install the dependency and, guess what, it has two more dependencies. So you spend an hour tracking down all the dependencies before you can install the application you wanted.

So there's a fix for this too -- package management frameworks that handle the dependency tracking and installation. Unfortunately there's not one fix here either. The RedHat side of the house uses a utility called "yum" to interface between the RPM installation framework on the local computer and an application repository. The Debian camp has a similar framework called "apt". Both accomplish the same goal (making it somewhat easier to install software on Linux computers) but at the cost making it significantly harder to package software for Linux computers.

To build Asterisk for "Linux" actually requires us to create 32 and 64-bit versions of the application (minimally) then package them for the current versions of RedHat (.rpm) and for Debian (.deb). We then have to create slightly different packages for older versions of those distributions and for derivatives and cousins. To support the most popular current distributions of "Linux" actually requires more than 20 separate packages be built and maintained.

If I had to point a finger at one factor that's kept Linux from succeeding as a "mainstream" operating system, I'd point to this kluge. Until you can build for "Linux 2.6" and hit 99% of systems running the 2.6 kernel, Linux won't have reached its true potential.

Monday, October 13, 2008

AsteriskNOW 1.5 Hits The Street

Yesterday we launched AsteriskNOW 1.5 which is a big deal in spite of the interim release number. It's not an upgrade for the original AsteriskNOW but a complete replacement and a huge step forward in terms of technology. I've outlined what's in the release on a post on the Digium company blog.

Thursday, October 2, 2008

Skype For Asterisk Response

I'm in the middle of reviewing the nearly 1000 applications to be part of the Skype For Asterisk program that was launched last Thursday at AstriCon. The applications include everything from one-man shops to universities with more than 30,000 students. The response has been absolutely overwhelming, and I'm looking forward to getting the beta rolling.

I'm also looking forward to starting in on the four initatives that I was priviledged to help announce on the pseudo-keynote on Wednesday, and the Asterisk Application Programming Interface (code name Pinemango) that was spec'd out during the AstriDevCon post-con event. AsteriskNOW, Asterisk Marketplace, a2m and Pinemango represent an amazing future for open source telephony.