Yohann Martineau, blog

Posts tagged development

asterisk SIP unregister not working

2013-08-03 15:40:17

For any reason, asterisk 11 requires a new SIP Call-ID to unregister a SIP account whereas RFC3261 SIP specification says that all REGISTERs should use the same Call-ID:

      Call-ID: All registrations from a UAC SHOULD use the same Call-ID
           header field value for registrations sent to a particular

           If the same client were to use different Call-ID values, a
           registrar could not detect whether a delayed REGISTER request
           might have arrived out of order.

Here is the paragraph in rfc3261 that proves that asterisk behavior is incorrect:

      6. The registrar checks whether the request contains the Contact
         header field.  If not, it skips to the last step.  If the
         Contact header field is present, the registrar checks if there
         is one Contact field value that contains the special value "*"
         and an Expires field.  If the request has additional Contact
         fields or an expiration time other than zero, the request is
         invalid, and the server MUST return a 400 (Invalid Request) and
         skip the remaining steps.  If not, the registrar checks whether
         the Call-ID agrees with the value stored for each binding.  If
         not, it MUST remove the binding.  If it does agree, it MUST
         remove the binding only if the CSeq in the request is higher
         than the value stored for that binding.  Otherwise, the update
         MUST be aborted and the request fails.

In my case, Call-ID is the same between register and unregister and unregister CSeq is higher than register CSeq.

If the same Call-ID is used between register and unregister, asterisk keeps returning 401 with a new challenge.

Nevertheless, apparently, asterisk accepts the same Call-ID for register-refreshes.

Opensips seems to accept different Call-ID between register and unregister, so let's go with that modification.

Peers updated accordingly.

Permanent link
telecom, protocol, peers, development, english


maven eclipse:eclipse maven-eclipse-plugin 2.9 NullPointerException

2012-10-04 00:16:13

If you have difficulties to generate eclipse project files (.project and .classpath) from a maven project on a debian based OS, this article is for you.

While running mvn eclipse:eclipse in my peers project, I was stuck with this issue:

[INFO] ------------------------------------------------------------------------
[INFO] Total time: 2.872s
[INFO] Finished at: Wed Oct 03 23:39:07 CEST 2012
[INFO] Final Memory: 10M/104M
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-eclipse-plugin:2.9:eclipse (default-cli) on project peers-doc: Execution default-cli of goal org.apache.maven.plugins:maven-eclipse-plugin:2.9:eclipse failed. NullPointerException -> [Help 1]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/PluginExecutionException

Actually, apparently, maven automatically seeks jvm instances on a debian host (in /usr/lib/jvm) and tries to extract MANIFEST.MF file from jre/lib/rt.jar file in each jvm folder.

It should be verified, but apparently, as soon as it finds an rt.jar file without manifest, it fails with this annoying NullPointerException.

I found that my system had 4 different JVMs:

  • java-1.5.0-gcj-4.4
  • java-6-openjdk
  • java-6-sun-
  • jdk1.7.0_07 (installed manually)
I found that the only installed jvm with no manifest in jre/lib/rt.jar was java-1.5.0-gcj-4.4, Thus, I removed jvm java-1.5.0-gcj-4.4 (debian package gcj-4.4-base) and it solved my issue.

Hope this helps someone...

Permanent link
java, debian, development, english


peers-0.4 small is beautiful!

2010-12-15 15:24:37

After more than one year of irregular development, bug fixing and refactoring, thinking, improving, thinking again and some short nights, a new release of peers is available!

In this release, you will find a brand new GUI, still based on swing, but using native look and feel.

javasound is still employed for microphone capture and contact's voice playback.

No more external library is employed in this release. Jrtp has been replaced with a new home made RTP stack. This RTP stack has been developed with the same keep it stupid simple philosophy as peers SIP stack.

As more and more people are using peers, interoperability tests have been performed against more IPBXs, gateways, hardphones and softphones. I don't have a complete list of compatible SIP elements, but this list is growing.

Amongst new features, the ability to configure your SIP account using Edit > Accout in menu bar will probably be the most important one. It implies that peers users no longer have to modify an xml file manually before peers startup.

If you are a voip customer and your internet service provider can give you a SIP account, you can try peers now to call from your PC. Depending on your internet service provider servers configuration, you may also receive calls on your PC using peers. Some service providers also enable you to place calls from anywhere in the world using your sip account and local rates towards fixed line phones.

Permanent link
english, development, internet service provider, java, peers, protocol


Send audio and video to X-Lite using ffmpeg

2010-04-10 11:28:46

Send Video

I've been struggling for long to find a way to send video to X-Lite. Now I can, using sipp and ffmpeg. I'm using a custom sipp script based on uas scenario. I've just added video media in uas script, in 200 OK SDP, using H263-1998 media description (and attributes) proposed in X-Lite SDP offer. This media contains size options (QCIF, CIF, etc.). Then I send INVITE to sipp from X-Lite using an account that does not need registration. I look at traces to find the port on which X-Lite is willing to receive video RTP packets, and I send a video to X-Lite using the following command:

  ffmpeg -re -i file.flv -f rtp -an -vcodec h263 -s 176x144 rtp://

file.flv is a video retrieved from youtube using any youtube grabber website.

But don't try this using ffmpeg as is, because ffmpeg always send RTP packets using payload type 96, which is a dynamic payload type. To make it work, you have to apply the following patch on ffmpeg, to use a payload type proposed by X-Lite, here 115:

index 5df101e..3c15a8b 100644
--- a/libavformat/rtpenc.c
+++ b/libavformat/rtpenc.c
@@ -78,7 +78,7 @@ static int rtp_write_header(AVFormatContext *s1)
     s->payload_type = ff_rtp_get_payload_type(st->codec);
     if (s->payload_type < 0)
-        s->payload_type = RTP_PT_PRIVATE + (st->codec->codec_type == AVMEDIA_TY
+        s->payload_type = 115;
     s->base_timestamp = ff_random_get_seed();
     s->timestamp = s->base_timestamp;

If I understand correctly, for the moment, it's not possible to manually set the payload type of RTP packets sent from ffmpeg. A long thread on ffmpeg mailing list seems to show that it's not possible yet.

This patch is (of course) not for production use, but at least, it works. Let's hope that ffmpeg will make this parameter configurable...

Send audio

To send audio, it's quite "easy", the following command should work out of the box :

  ffmpeg -re -i file.flv -vn -acodec pcm_mulaw -ar 8000 -ac 1 -f rtp rtp://

Here, the trick is to force ffmpeg to use 172 UDP packets, because X-Lite only accept RTP packets which payload size is exactly 160. RTP (standard) header size is 12 bytes, thus pkt_size must be 172.

Permanent link
protocol, multimedia, development, english


Compiler un firmware de clubinternet box

2009-10-29 14:48:36
Date originale : 5 février 2007

voici un petit tutorial pour compiler un firmware de clubinternet box, et ainsi pouvoir peronnaliser les fonctions de sa boîte.

Les différentes étapes à suivre sont les suivantes :

  • récupérer les sources du firmware de la clubinternet box (dans mon cas le modèle est AH4222, mais celà devrait être assez proche pour un modèle AH4021),
  • installer la chaîne de compilation fournie,
  • corriger les petites erreurs des sources fournies,
  • compiler les sources et créér une image de système de fichier à flasher sur la ROM de la boîte,
  • transférer cette image sur la boîte.
Cet article décrit la marche à suivre pour compiler ces sources depuis un système GNU/Linux, plus particulièrement Debian Etch.

Obtention des sources

Pour pouvoir compiler les sources, il faut d'abord les obtenir les sources du firmware de la clubinternet box sont disponibles ici. Les versions du firmware doivent à priori évoluer souvent, donc il est possible que ce lien ne marche pas éternellement. En revanche, lorsque ces sources sont mises à disposition du public, une annonce est effectuée sur le forum technique de club-internet, dans la rubrique "Modem ADSL et Téléphonie clubinternet.box et AH-4021". Cette anonce est acutellement intitulée "Code source du firmware Hitachi (V44)", elle contient un lien vers les sources du firmware.

L'accueil des forums de club-internet est accessible ici. Attention, ces sources font quand même environ 84Mo, prévoir un peu de temps pour les télécharger, donc.

Deuxième étape : exploration du contenu de cette archive.

Cette archive contient elle-même deux autres archives et un script d'installation. Une des deux archives (bcm963xx_AH4222.01.2.01L.300L01.V44-08_consumer.tar.gz) contient véritablement le code source du firmware et la seconde archive (bcm963xx_uclibc_crosstools_3.4.2_0.9.27.tar.gz) contient la chaîne de compilation (uclibc) nécessaire pour compiler les sources du firmware avec la bonne cible.

La chaîne de compilation est fournie sous forme de deux paquets rpm, si vous utilisez une distribution gerrant directement les rpm (Mandriva, RedHat, Suse, etc.) vous pouvez vous contenter de lancer le script d'installation en root. L'installation à partir du script d'installation "consumer_install" va créér deux répertoires sous /opt. Si, en revanche vous avez une distribution utilisant des paquets au format debian (Debian, Ubuntu, etc.), comme c'est mon cas, il va falloir décompresser l'archive contenant les deux rpms, puis transformer ces paquets RPM en paquets deb.

Pour cela, on peut utilser le programme alien accouplé à rpm pour générer des paquets .deb à partir de paquets .rpm. La commande suivante, lancée en root permet donc d'installer les programmes nécessaires :

# apt-get install alien rpm

Ensuite pour convertir les paquets il suffit de lancer alien avec en paramètre le paquet à convertir.

# alien uclibc-crosstools-mips.i386.rpm
# alien -scripts uclibc-crosstools-common.i386.rpm

Attention : il faut rajouter l'option -scripts pour le paquet uclibc-crosstools-common.i386.rpm car ce paquet contient des scripts de post-installation, de pré-installation, ou d'un autre type, mais il est nécessaire d'inclure ces scripts dans le paquet généré (pas fait par défaut).

Deux paquets sont normalement disponibles au format .deb maintenant. Pour les installer, il suffit donc de lancer la commande suivante en root :

# dpkg -i *.deb

Les sources du firmware n'utilisent pas directement l'emplacement par défaut de la chaîne de compilation, il est donc nécessaire de rajouter un lien vers la chaîne :

# ln -s /opt/toolchains /opt/toolchains_3_00
Victoire ! La chaîne de compilation est désormais installée, et opérationnelle !

Patchs à effectuer

Avant de se casser les dents sur la compilation, mieux vaut effectuer quelques modifications dans les sources fournies.

Tout d'abord, il est nécessaire de patcher la génération de configuration du noyau linux. Il faut modifier le fichier suivant :

Dans ce fichier, il faut remplacer toutes les occurences de current_menu par un autre nom non déjà pris, par exemple current_mconf_menu.

Ensuite, il faut patcher le système de gestion de la configuration de la clubinternet box.

Dans le fichier :

Supprimer les références à sha1.h, c'est à dire :
  • supprimer la ligne #include "sha1.h"
  • supprimer tout ce qu'il y a après la ligne :
    /********************** end base64 decode and encode functions **********************/
Cela correspond aux méthodes liées à sha1.h dont l'implémentation n'est pas fournie.


Ouf, la compilation va maintenant pouvoir commencer.

Les cibles disponibles pour la compilation sont présentes dans le répertoire targets des sources du firmware, désormais installées dans /opt/bcm963xx_router. Dans notre cas, il y a un répertoire 96348GWV ou similaire qui nous donne le nom de la cible à passer en paramètre à la compilation.

La commande à taper (toujours en root) pour lancer la compilation est donc la suivante :

# make PROFILE=96348GWV
Là, on croise bien fort les doigts et quelques minutes plus tard, une image de disque ROM a été générée et est prête à être transférée dans la mémoire de la clubinternet box. Si la compilation s'est bien passée, un message l'indique en donnant le nom de l'image du système de fichier à ralonge qui a été générée. Dans mon cas le nom de l'image générée est la suivante :

Transfert de l'image

Maintenant que nous avons notre image, le plus dûr à été effectué. Il reste tout de même à installer sur sa machine un serveur tftp pour pouvoir transférer l'image sur la boîte. En effet, lorsque la boîte effectue ses mises à jour en tant normal, elle transfert son image en utilisant un client tftp un peu allégé. Ce client récupère en tant normal l'image sur le site suivant : tftp-ht.voip.club-internet.fr mais nous allons désormais lui faire utiliser notre machine, sur laquelle vient d'être générée une image toute neuve.

Sous debian, il suffit d'utiliser la commande apt-get install tftpd pour installer un serveur tftp, il doit certainement y avoir l'équivalent pour les distributions au format rpm. La racine du serveur tftp sous debian se trouve dans /srv/tftp, il suffit donc de copier l'image générée dans ce répertoire.

Ensuite on peut se connecter via telnet à la clubinternet box :

$ telnet
L'utilisateur est root, et le mot de passe est clubadmin. Une fois connecté, une invite de commande commançant par > s'affiche. Il est désormais possible de transférer l'image et de la flasher immédiatement avec la commande suivante :
> tftp -g -f bcm96348GWV_fs_kernel_AH4222.
-g est l'option correspondant à get
-f pour spécifier le nom du fichier distant à transférer et l'adresse de la machine sur laquelle on est à passer à la fin (éventuellement à adapter)

Si vous vous trompez de fichier ou que vous ne spécifiez pas une image valide à transférer, la clubinternet box va le détecter et à son prochain reboot, elle téléchargera l'image du firmware depuis le site de club-internet.

Après le "flashage", la boîte redémarre, il faut lui laisser quelques minutes, et si après ces quelques minutes vous pouvez vous connecter à internet, c'est gagné ! vous avez réussi à installer votre image de système de fichier sur la boîte !

Personnaliser sa boîte

Maintenant que nous savons compiler notre image et la transférer sur la boîte, nous allons (enfin) pouvoir commencer à faire des choses amusantes avec la boîte. Nous allons réalser les étapes suivantes :

  • écrire un "Hello world" en c,
  • le compiler au bon format,
  • placer le binaire au bon endroit,
  • recompiler l'image,
  • la transférer,
  • tester notre super programme.
Ecrire un fichier helloworld.c :

int main() {
  printf("Hello, world!\n");
  return 0;
C'est rudimentaire, mais très utile pour pouvoir effectuer des tests simples.

Maintenant, nous pouvons compiler notre premier programme avec la chaîne de compilation :

/opt/toolchains/uclibc-crosstools/bin/mips-uclibc-gcc helloworld.c
Nous avons donc maintenant un fichier binaire a.out. Ce fichier est au format MIPS, nous pouvons le vérifier avec la commande suivante :
# file a.out
a.out: ELF 32-bit MSB executable, MIPS, MIPS-I version 1 (SYSV), dynamically linked (uses shared libs), not stripped

Une fois que nous avons ce fichier binaire exécutable sur la clubinternet box, nous pouvons le placer au bon endroit dans l'arborescence du système de fichier utilisé pour créér l'image de disque ROM :

# cp a.out /opt/bcm963xx_router/targets/fs.src/usr/bin
les fichiers exécutables que l'on génère sont à placer dans /usr/bin dans /opt/bcm963xx_router/targets/fs.src et non dans /bin, car ces programmes ne concernent pas le fonctionnement du système directement. Et surtout des vérifications sont effectuées lors de la compilation sur la suppression des entêtes et autres données "inutiles" (strip) dans le programme sous forme de fichier binaire.
Maintenant, tout est prêt pour regénérer l'image de disque ROM (une nouvelle image est générée et l'ancienne n'est pas écrasée). Voir plus haut. Idem pour le transfert de l'image.

Une fois que l'image a été générée, on peut déjà vérifier que rien n'a été cassé en essayant de se connecter à internet. Si tout fonctionne, nous pouvons continuer et tester notre programme.
Il faut donc à nouveau se connecter sur la boite (telnet root/clubadmin). Mais maintenant que l'invite en > apparaît, nous allons lancer un shell pour pouvoir exécuter notre programme. Il suffit de taper la commande suivante :

> sh

BusyBox v1.00 (2007.02.04-15:52+0000) Built-in shell (msh)
Enter "help" for a list of built-in commands.

Nous pouvons maintenant enfin lancer notre programme hors du commun avec la commande suivante :
# /usr/bin/helloworld
Hello, world!
Victoire, nous pouvons exécuter le code que nous voulons sur la boîte !!!


Un client http (wget) est directement fourni sur la boîte, nous aurions donc pu simplement compiler le programme, le mettre sur un serveur web et le transférer avec wget a.out en le plaçant dans la partition /var accessible en écriture sur la boîte, puis le rendre exécutable (chmod 755) et le lancer directement. En revanche, le fait d'insérer notre programme dans /var limite sa taille fortement (en général, entre 50 et 150 ko sont disponibles dans /var), alors que la ROM de la club internet box peut contenir jusqu'à 4,2Mo de données. Mais surtout /var n'est pas l'endroit adequat pour l'exécution des programmes sous linux.

Voilà, j'espère que ce petit tutorial aura pu vous aider...

Permanent link
linux, internet, embedded systems, development, français


Peers : nouveau softphone SIP

2009-03-31 22:00:52
Date originale : 2 décembre 2007


Après plusieurs mois de développement, la première version de Peers est sortie ! Peers est un softphone SIP minimaliste écrit en java. Peers est donc un logiciel permettant de téléphoner d'un ordinateur à un autre sur un réseau local. Pour appeler une personne, il suffit de taper : sip: avec la bonne adresse. L'ordinateur appelé décroche automatiquement et l'appel est établi. Ensuite, l'appelé ou l'appelant peuvent raccrocher avec le bouton "hang up".

Pourquoi ?

En effet, il existe déjà d'autres piles SIP écrites en java, alors pourquoi se lancer dans cette implémentation ? Pour deux raisons. Premièrement, il n'existe à ma connaissance pas plus de deux implémentations open source en java d'une pile SIP :

  • Jain-sip, implémentée par NIST, un institut de recherche américain,
  • MjSip, implémentée par l'université de Parme.
Dans les deux cas, ces implémentations sont des implémentations complètes de la spécification de SIP : la RFC 3261, c'est-à-dire qu'il est possible de créér tous les éléments d'un réseau SIP grâce à ces implémentations : User-Agent, Proxy, Registrar, etc. Or, réaliser l'abstraction entre ces différents rôles ajoute une complexité importante aux implémentations. De plus, les ressources nécessaires dans la vie de tous les jours pour implémenter ces rôles sont très différentes. Je m'explique, un User-Agent est un softphone, c'est donc un logiciel qui va se lancer sur l'ordinateur d'un utilisateur. Cet utilisateur utilisera des fonctions éventuellement avancées au niveau media mais pas au niveau contrôle de session. SIP intervient au niveau du contrôle de sessions. Le User-Agent est en gros un logiciel client. Pour les autres rôles (Registrar, Proxy, ...) il s'agit d'implémenter des serveurs n'ayant aucune interface utilisateur et étant optimisés au maximum pour gérer un maximum de sessions en parallèle ou un maximum de messages, etc.

Pour en revenir aux autres implémentations, elles permettent donc de réaliser tous les éléments d'un réseau SIP, mais ce n'est pas le but de Peers. Le but de Peers est d'écrire un logiciel permettant le maximum d'interactions possibles avec les autres utilisateurs, et que ces fonctionnalités soient facilement évolutives. L'implémentation de Peers se veut simple. Malgré ses 10 000 lignes de code (environ), l'implémentation de peers se veut minimaliste et évolutive. C'est son évolutivité qui lui donne se volume. Le but de Peers n'est pas de devenir un serveur, mais bel et bien d'être lancé sur un poste utilisateur.

La deuxième raison est la possibilité d'apprendre par la pratique. Rien n'est plus formateur que de comparer son implémentation avec les plus réputées pour voir d'où viennent les problèmes, et ceci tout en lisant plusieurs fois les RFCs pour bien comprendre les concepts et ne pas tomber dans une implémentation uniquement empirique. SIP est pour moi un protocol nouveau, il y a un an, je ne connaissais rien à SIP.

Pour plus d'informations, vous pouvez me contacter par mail, voir ma page contact.

Permanent link
protocol, peers, multimedia, java, internet, development, français