Introduction
Architecture of a Linux Telephone Interface
Install Drivers and Libraries
Select and Install the Softmodem
A Simple Answering Machine
Next Steps ...
The requirements for the project are:
- An Intel 537 based modem (softmodem)
- A PCI slot that does not share interrupts
Intel 537 based modems are readily available for less than ten dollars. You can probably find one on the web by searching on the terms "price" and "intel 537". The driver we are going to use requires the Intel chip, so be sure you have the right modem before starting.
The driver for the modem card is the wcfxo module. This interfaces to a higher level driver called "zaptel". The division of the driver into two pieces helps the Asterisk developers minimize how much code they need to write for new types of PC telephony interface cards. The zaptel driver delivers a 64 Kbps stream of mu-law samples to the user space application. Zaptel also has IO control routines (ioctl's) to go on-hook, off-hook, and to indicate that the phone line is ringing.
The Zapata library (libzap) processes the 64 Kbps stream of data to extract caller ID and DTMF signals. The competence of libzap is why our answering machine application is so simple.Our answering machine is pretty minimal as telephony applications go. It extracts and displays to standard out the caller ID information for incoming calls. If the phone rings more than four times, it answers the phone and plays a greeting. The greeting message asks the caller to press one to leave a message. Having the caller press a button eliminates messages from so called "bulk dialers". Voice mail is left as mu-law encoded data in a file with the date and time encoded into the file name.
http://ftp.digium.com/pub/zaptel/
Untar the file, do a 'make linux26' and a 'make install' (as root).
If you are using udev, be sure to follow the directions in README.udev.
Specifically, you need to add the following lines to your
/etc/udev/rules.d/50-udev.rules file:
KERNEL="zapctl", NAME="zap/ctl"
KERNEL="zaptimer", NAME="zap/timer"
KERNEL="zapchannel", NAME="zap/channel"
KERNEL="zappseudo", NAME="zap/pseudo"
KERNEL="zap[0-9]*", NAME="zap/%n"
I run the answering machine as myself so I've added the following
line to the udev permissions file
(/etc/udev/permissions.d/00-udev.permissions).
zap/*:bobsmith:bobsmith:660
The final piece of zaptel configuration is to tell it that we have
one interface to the telephone "central office". Edit /etc/zaptel.conf
and add the following line to the end.
fxsks=1
If you don't live in the US, you should should make one other change to zaptel.conf. You need to uncomment the line with your country code and make that country code the defaultzone.
http://ftp.digium.com/pub/zaptel/old/
Untar the file, do a 'make' and a 'make install' (as root). The Zapata library does not need any configuration.
To call it a "modem" is not quite correct. It is really more of a "phone line interface". Its 64 Kbps stream is 8000 bytes per second, which the wcfxo/zaptel driver delivers in 8 byte chunks. This means a thousand interrupts per second! It is the interrupt load that makes installing the modem card a little tricky. You need to install it in a PCI slot with an interrupt that is not shared by any other device. Check the documentation for your motherboard to find which interrupts are used for which slots and how those interrupts are used by the internal peripherals. If you are very unlucky, you may find that the interrupt for every slot on your motherboard is shared and used. You can try disabling internal peripherals but wcfxo just won't work on some motherboards.
The other, less common problem is that the wcfxo driver does not
recognize your modem. To fix this you need to edit the wcfxo_pci_tbl
table near the bottom of wcfxo.c in the zaptel build directory.
Use 'lspci -nv' to get the needed vendor ID, product ID, and
subsystem ID. The following vendor, product, and subsystem IDs are
already recognized by wcfxo:
- e159:0001 8085
- e159:0001 8086
- e159:0001 8087
If you've completed the hardware and software installation, you can verify your system with a few commands.
Install the modules and examine the resulting syslog output.
#modprobe zaptel
#modprobe wcfxo
#tail /var/log/messages
Sep 18 23:30:41 kernel: Zapata Telephony Interface Registered on major 196
Sep 18 23:30:51 kernel: PCI: Found IRQ 5 for device 0000:00:0b.0
Sep 18 23:30:51 kernel: PCI: Sharing IRQ 5 with 0000:00:07.5
Sep 18 23:30:51 kernel: wcfxo: DAA mode is 'FCC'
Sep 18 23:30:51 kernel: Found a Wildcard FXO: Generic Clone
Sep 18 23:30:51 kernel: Registered tone zone 0 (United States / North America)
Don't worry about the "Sharing IRQ 5" log message. This reports
that the IRQ can be shared but does not imply that another Linux
device is using it.
An lsmod should show the following three modules.
# lsmod
Module Size Used by
wcfxo 10848 0
zaptel 185572 3 wcfxo
crc-ccitt 1664 1 zaptel
Verify that the wcfxo driver is generating a thousand interrupts
per second and that it is not shared with any other devices.
cat /proc/interrupts; sleep 10; cat /proc/interrupts
The wcfxo entry in /proc/interrupts should be on a line by itself,
and the interrupt count should have gone up by ten thousand during
the above 10 second sleep. If wcfxo is not on a line by itself, you
need to move the modem to another PCI slot. Specifically, you want
something like this:
5: 3003856 XT-PIC wcfxo
not something like this: 9: 0 XT-PIC uhci_hcd, uhci_hcd, wcfxo
The zaptel driver includes a utility to view the driver configuration.
Use it to verify that it has one interface. If this fails, check the
fxsks=1 line in the configuration file.
# ztcfg -v
Zaptel Configuration
======================
1 channels configured.
gcc -lzap -o answering_machine answering_machine.c
Run the program with the command: ./answering_machine
The program expects to find an 8 KHz mu-law encoded greeting
message called "leave_a_msg.ul" in the working directory.
You can record the greeting using any tool you like and then
convert the WAV file to mu-law using sox. The command
is:
sox leave_a_msg.wav leave_a_msg.ul
Sox interprets files with the .ul extension as mu-law encoded
audio at 8 KHz. You can hear your voice mail using the play
command. For example:
play 2005_09_22_13_30_22.ul
The hard work in the answering machine is done by the Zapata library. It does the caller ID, DTMF tone detection, and reads and writes mu-law audio files. Here is a skeleton of the code in the answering machine.
zp = zap_open("/dev/zap/1", 0);
while (1) {
/* Wait for a ring and get caller ID info */
zap_clid(zp, cidnumber, cidname);
{ Display caller ID to user. Do logs or black list checking here. }
/* Wait for an additional RINGS-1 rings before answering */
zap_waitcall(zp, (RINGS - 1), ZAP_OFFHOOK, TM_OUT/1000);
/* Tell Zapata that we want DTMF digits */
zap_digitmode(zp, ZAP_DTMF) && zap_clrdtmf(zp);
/* Play our outgoing message. Abort on DTMF or hang-up. */
zap_playf(zp, "leave_a_msg.ul", ZAP_DTMFINT | ZAP_HOOKEXIT);
{ Continue if caller hung up }
/* Wait up to TM_OUT ms for the caller to enter a DTMF digit */
zap_getdtmf(zp, 1, (char *)0, 0, 0, TM_OUT, ZAP_HOOKEXIT);
{ Hang-up/continue if time-out and no DTMF digit. }
/* Get the DTMF digit the caller entered. Hang-up if wrong digit */
pDigits = zap_dtmfbuf(zp);
{ Hang-up/continue if caller entered wrong digit }
/* Save voice mail to 'date_time' file. */
zap_recf(zp, date_time, 0, ZAP_BEEPTONE | ZAP_SILENCEINT);
/* Done with message. Hang-up and wait for next call. */
zap_sethook(zp, ZAP_ONHOOK);
}
}
The above code should give you a feel for how to write telephony applications using the Zapata library. The library also has routines that you can use to make outgoing calls and to help make conference calls.
For a simple answering machine, this program works surprisingly well. Its simplicity is its best feature.
If we were to add features to the answering machine, we would
probably add:
The Zapata library uses blocking IO, making it a little difficult to use a select() loop to manage a user interface while waiting for incoming calls. Perhaps a threaded application could step around this problem.