Copyright © 2005 Bob Smith
Copyright © 2005 Florent Revelut
Copyright © 2005 Joëlle Cornavin
Article paru dans le n°120 de la Gazette Linux de novembre 2005.
Traduction française par Florent Revelut
<florent POINT revelut CHEZ free POINT fr>
.
Relecture de la traduction française par Joëlle Cornavin
<jcornavi CHEZ club TIRET internet POINT fr>
.
Article publié sous Open Publication License. La Linux Gazette n'est ni produite, ni sponsorisée, ni avalisée par notre hébergeur principal, SSC, Inc.
Cet article décrit comment construire un répondeur téléphonique inspiré de Linux à l'aide d'un Winmodem (modem logiciel) bon marché. Nous expliquerons comment installer les pilotes et les bibliothèques, comment choisir et installer la carte modem la plus adaptée. Notre programme de répondeur téléphonique se compose de quelques centaines de lignes de code écrites en C dans un seul fichier. Si vous avez déjà utilisé un téléphone, vous ne devriez avoir aucun problème à comprendre le code.
Les prérequis pour ce projet sont les suivants :
Une carte modem reposant sur une puce Intel® 537 (softmodem, modem logiciel) ;
Un emplacement PCI (Peripheral Component Interconnect, interconnexion de composants) qui ne partage pas d'interruptions.
Les cartes modem reposant sur des puces Intel® 537 sont disponibles pour moins de 9 euros actuellement. Comme le pilote que nous allons utiliser requiert cette puce, assurez-vous d'avoir le modem est correct avant de commencer.
Notre répondeur utilise des pilotes et des bibliothèques qui font partie du PBX (Private Branch eXchange, commutateur privé) Asterisk open source. Asterisk peut fonctionner en tant que répondeur téléphonique, mais c'est une application énorme et qui souffre d'une forte courbe d'apprentissage en terme d'installation et de configuration. Le paquetage Asterisk décompressé fait plus de 16 méga-octets, soit bien plus que les 5 kilo-octets de notre fichier source. L'architecture globale de notre répondeur téléphonique est présentée dans le diagramme ci-dessous.
Le pilote de la carte modem est le module wcfxo, qui s'interface vers un pilote de plus haut niveau appelé zaptel. La division du pilote en deux parties aide les développeurs Asterisk à minimiser la quantité de code qu'ils doivent écrire pour de nouveaux types de cartes d'interface téléphonique pour PC. Le pilote zaptel fournit à l'application de l'espace utilisateur un flux d'échantillons mu-law de 64 kb/s. zaptel comporte également des IOCTL IOCTL (IO Control Routines, routines de contrôle des entrées/sorties) pour décrocher la ligne, raccrocher ou indiquer que la ligne téléphonique sonne.
La bibliothèque Zapata (libzap) traite le flux de données de 64 kb/s pour extraire l'identifiant de l'appelant et les signaux DTMF (Dual Tone MultiFrequency, multifréquence à double tonalité). Les capacités de la libzap explique pourquoi notre répondeur est aussi simple.
Notre répondeur téléphonique correspond au strict minimum en tant qu'application téléphonique. Il extrait et affiche les informations d'identifiant de l'appelant pour les appels entrants. Si le téléphone sonne plus de quatre fois, il décroche et lit un message d'accueil. Celui-ci demande à l'appelant d'appuyer sur la touche « 1 » pour laisser un message. Obliger l'appelant à appuyer sur un bouton élimine les messages de ce qu'on appelle les « systèmes d'appels automatiques » (bulk dialers). Le message vocal est enregistré sous forme de données encodées en mu-law dans un fichier dont le nom contient la date et l'heure.
Notre répondeur téléphonique requiert les pilotes zaptel et la bibliothèque Zapata, disponibles tous les deux sur le site web d'Asterisk.
Deux pilotes, wcfxo et zaptel, sont nécessaires. Ils se trouvent l'un et l'autre dans le paquetage zaptel. Vous pouvez obtenir ce paquetage via le lien Downloads sur la page d'accueil de Asterisk ou directement sur le site de Digium, qui héberge le site de téléchargement :
http://ftp.digium.com/pub/zaptel/zaptel-1.0.9.2.tar.gz
Désarchivez le fichier, faites un make linux26 et un make install (en tant que root). Si vous utilisez udev, suivez scrupuleusement les directives du fichier README.udev (en anglais). En particulier, vous devez ajouter les lignes suivantes à votre fichier /etc/udev/rules.d/50-udev.rules :
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" |
Comme j'ai démarré le répondeur sous mon nom d'utilisateur (bobsmith), j'ai ajouté la ligne suivante au fichier de permissions udev (/etc/udev/permissions.d/00-udev.permissions) :
zap/*:bobsmith:bobsmith:660 |
La dernière partie de la configuration de zaptel consiste à lui indiquer que nous avons une interface au téléphone « central téléphonique ». Modifiez le fichier /etc/zaptel.conf et ajoutez la ligne suivante à la fin :
fxsks=1 |
Si vous ne vivez pas aux États-Unis, un autre changement dans le fichier zaptel.conf sera nécessaire. Vous devez décommenter la ligne contenant votre code de pays et faire de ce code de pays la zone par défaut.
Du fait que Asterisk n'utilise plus la bibliothèque zapata, cette dernière a été déplacée dans le répertoire old sur le site de téléchargement :
http://ftp.digium.com/pub/zaptel/old/zapata-0.9.1.tar.gz
Désarchivez le fichier, faites un make et un make install (en tant que root). La bibliothèque Zapata ne nécessite aucune configuration.
Comme indiqué plus haut, vous devez être sûr de disposer d'un modem compatible avec la puce Intel® 537. Ces modems devraient être faciles à trouver et relativement bon marché.
L'appeler « modem » n'est pas tout à fait correcte. Il s'agit en effet plus d'une « interface vers une ligne téléphonique » dont le flux de 64 kb/s apporte 8 000 octets par seconde, que le couple de pilotes wcfxo/zaptel apporte en blocs de 8 octets. Cela signifie concrètement un millier d'interruptions par seconde ! C'est cette charge sur les interruptions qui rend l'installation de la carte modem un peu délicate. Vous devez installer la carte dans un emplacement PCI qui n'est pas partagé avec un autre périphérique. Vérifiez dans la documentation de votre carte mère pour savoir quels emplacements utilisent quelles interruptions et comment les périphériques internes emploient ces interruptions. Si vous n'avez vraiment pas de chance, vous constaterez peut-être que l'interruption pour chaque emplacement est partagée et utilisée. Vous pouvez essayer de désactiver des périphériques internes, mais il y a un risque que wcfxo ne fonctionnera tout simplement pas sur certaines cartes mères.
L'autre problème, moins courant, est que le pilote wcfxo ne reconnaisse pas votre modem. Pour le résoudre, modifiez la table wcfxo_pci_tbl vers la fin du fichier wcfxo.c dans le répertoire de compilation de zaptel. Utilisez lspci -nv pour récupérer l'identifiant du fabricant, du produit et du sous-système. Les identifiants suivants de fabricant, de produit et de sous-système sont déjà reconnus par wcfxo :
e159:0001 8085
e159:0001 8086
e159:0001 8087
Si vous avez terminé l'installation matérielle et logicielle, vous pouvez vérifier votre système en quelques commandes. Installez les modules et examinez la sortie syslog obtenue :
#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) |
Ne vous inquiétez pas du message « Sharing IRQ 5 ». Il vous informe que l'IRQ peut être partagée, mais cela n'implique pas qu'un autre périphérique Linux s'en sert en ce moment. Un lsmod devrait afficher les trois modules :
# lsmod Module Size Used by wcfxo 10848 0 zaptel 185572 3 wcfxo crc-ccitt 1664 1 zaptel |
Vérifiez que le pilote wcfxo génère un millier d'interruptions par seconde et qu'elles ne sont pas partagées avec tout autre périphérique :
cat /proc/interrupts; sleep 10; cat /proc/interrupts |
L'élément wcfxo dans /proc/interrupts devrait être une ligne à elle seule et le compteur d'interruption devrait avoir avancé de dix mille pendant les dix secondes d'attente ci-dessus. Si wcfxo n'a pas une ligne pour lui tout seul, vous devez déplacer le modem sur un autre emplacement PCI. Plus précisément, vous voulez quelque chose comme :
5: 3003856 XT-PIC wcfxo |
et non quelque chose comme :
9: 0 XT-PIC uhci_hcd, uhci_hcd, wcfxo |
Le pilote zaptel contient un utilitaire pour visualiser sa configuration. Servez-vous en pour vous assurer qu'il a une interface. Si ce test échoue, vérifiez que vous avez la ligne fxsks=1 dans votre fichier de configuration.
# ztcfg -v Zaptel Configuration ==================== 1 channels configured. |
Le code pour le répondeur téléphonique est un seul fichier C qui est disponible ici. Compilez le programme avec la commande suivante :
gcc -lzap -o answering_machine answering_machine.c |
Lancez le programme avec la commande suivante :
./answering_machine |
Le programme s'attend à trouver un message d'accueil encodé en mu-law à 8 kHz appelé « leave_a_msg.ul » dans le répertoire en cours. Vous pouvez enregistrer l'annonce avec l'utilitaire de votre choix et ensuite convertir le fichier WAV en mu-law à l'aide de sox. La commande à utiliser est la suivante :
sox leave_a_msg.wav leave_a_msg.ul |
Sox interprète les fichiers portant l'extension .ul comme un format audio encodé en mu-law à 8 kHz. Vous pouvez entendre vos messages vocaux en utilisant la commande play. Par exemple :
play 2005_09_22_13_30_22.ul |
Le travail difficile dans le répondeur téléphonique est effectué par la bibliothèque Zapata. Elle gère la détection de l'identifiant de l'appelant, des signaux DTMF, lit et écrit les fichiers audio mu-law. Voici le squelette du code du répondeur téléphonique :
zp = zap_open("/dev/zap/1", 0); while (1) { /* Attendre une sonnerie et obtenir les informations d'identifiant de l'appelant */ zap_clid(zp, cidnumber, cidname); { Afficher l'identifiant de l'appelant à l'utilisateur. Créer des journaux ou faire un contrôle de liste noire ici. } /* Attendre encore RINGS-1 sonneries avant de répondre */ zap_waitcall(zp, (RINGS - 1), ZAP_OFFHOOK, TM_OUT/1000); /* Informer Zapata que nous attendons des chiffres par signaux DTMF */ zap_digitmode(zp, ZAP_DTMF) && zap_clrdtmf(zp); /* Lire notre message sortant. Interrompre lors de la réception de signaux DTMF ou en cas de raccrochage. */ zap_playf(zp, "leave_a_msg.ul", ZAP_DTMFINT | ZAP_HOOKEXIT); { Continuer si l'appelant a raccroché } /* Attendre pendant TM_OUT ms que l'appelant saisisse un chiffre et envoie un signal DTMF */ zap_getdtmf(zp, 1, (char *)0, 0, 0, TM_OUT, ZAP_HOOKEXIT); { Raccrocher/continuer en cas de temps imparti dépassé et s'il n'y a pas de signaux DTMF. } /* Obtenir le chiffre par signal DTMF que l'appelant a saisi. Raccrocher si le chiffre est erroné */ pDigits = zap_dtmfbuf(zp); { Raccrocher/continuer si l'appelant a saisi un chiffre erroné. } /* Enregistrer les messages vocaux dans le fichier 'date_heure' */ zap_recf(zp, date_time, 0, ZAP_BEEPTONE | ZAP_SILENCEINT); /* Terminé avec le message. Raccrocher et attendre le prochain appel. */ zap_sethook(zp, ZAP_ONHOOK); } } |
Le code ci-dessus devrait vous donner une idée de la manière d'écrire des applications téléphoniques à l'aide de la bibliothèque Zapata. La bibliothèque a également des fonctions pour passer des appels sortants et mettre en place des conférences téléphoniques.
Pour un répondeur téléphonique simple, ce programme fonctionne étonnament bien. En fait, sa simplicité est sa meilleure qualité.
Si l'on devait ajouter des fonctionnalités supplémentaires à ce répondeur, on ajouterait probablement :
L'accès à distance aux messages vocaux : nous devrions être en mesure de récupérer nos messages vocaux sur une ligne téléphonique. Les enregistrer dans un fichier nous donne déjà un accès distant. Cependant...
Le routage de l'identifiant de l'appelant : l'appel serait routé en fonction du numéro de téléphone de l'appelant. Certains appelants accéderaient directement à la messagerie vocale.
La captures des appels sortants : le répondeur téléphonique devrait être en mesure de journaliser le numéro appelé et la durée des appels sortants.
L'enregistrement des appels en cours : ne serait-il pas pratique de pouvoir juste appuyer sur une touche pour que votre appel actuel soit enregistré ? Ce serait une méthode beaucoup plus fiable pour prendre des notes pendant un appel. Bien sûr, vous seriez amené à informer votre interlocuteur que vous enregistrez l'appel et vous feriez biper la machine toutes les dix secondes, ou similaire.
Une interface web : il pourrait être agréable d'avoir une interface web pour configurer le répondeur. Quelque chose comme la bibliothèque Run Time Access pourrait se révéler utile. (Consultez http://www.runtimeaccess.com .)
La remise par courrier électronique des messages vocaux : nous pourrions convertir les fichiers de courrier vocal du mu-law en WAV et nous les faire envoyer par courrier électronique.
La transmission des messages/avertissement par récepteur de radio-messagerie : il s'agit d'utiliser la capacité de libzap à émettre des appels sortants pour informer un récepteur de radio-messagerie qu'il y a un nouveau message ou de demander à l'application d'appeler notre téléphone portable et de lire le message vocal.
La bibliothèque Zapata utilise des entrées/sorties bloquantes, ce qui complique un peu l'emploi d'une boucle select()
pour gérer une interface utilisateur lors de l'attente des messages entrants. Peut-être une application à plusieurs fils d'exécution (threaded) contournerait-elle le problème.
Bob est électronicien amateur et programmeur Linux. Il est un des auteurs de Linux Appliance Design qui doit être publié par No Starch Press®.