Aller au contenu

Le protocole SIP — le langage du contrôle d'appel

Ce qu'on cherche à comprendre : comment deux téléphones IP négocient qu'un appel commence, qu'il continue, qu'il se finit. À la fin de ce chapitre, lire un trace SIP doit être aussi naturel que lire un échange HTTP dans Chrome DevTools.

Le mental model d'abord

SIP est un protocole texte (comme HTTP), request/response, qui transporte uniquement la signalisation — pas l'audio. Quand vous appelez quelqu'un :

  1. Votre téléphone envoie un message SIP "INVITE" au serveur
  2. Le serveur le route vers le téléphone destinataire
  3. Le destinataire répond "200 OK"
  4. Votre téléphone confirme avec "ACK"
  5. À ce moment, l'audio (RTP) commence à circuler — directement entre les deux téléphones, généralement, sans passer par le serveur.
  6. Quand un côté raccroche, il envoie "BYE", l'autre répond "200 OK"

Le serveur SIP (Asterisk, FreePBX) est un chef d'orchestre qui coordonne qui parle à qui. Il ne porte (généralement) pas la voix elle-même.

À retenir : SIP = qui appelle qui, RTP = la voix. Quand vous diagnostiquez "il y a un appel mais pas d'audio" → le problème est sur RTP, pas sur SIP. Quand vous diagnostiquez "le téléphone ne sonne pas du tout" → le problème est sur SIP, pas sur RTP.

Anatomie d'un message SIP

Comme HTTP. Une start-line, des headers, parfois un body.

Exemple — INVITE

INVITE sip:1001@pbx.technotrement.com SIP/2.0
Via: SIP/2.0/UDP 192.168.1.50:5060;branch=z9hG4bK-524287-1
From: "Arno" <sip:1002@pbx.technotrement.com>;tag=8e3f4a
To: <sip:1001@pbx.technotrement.com>
Call-ID: a1b2c3d4@192.168.1.50
CSeq: 1 INVITE
Contact: <sip:1002@192.168.1.50:5060>
Max-Forwards: 70
User-Agent: Yealink T48S 66.86.0.40
Content-Type: application/sdp
Content-Length: 312

v=0
o=- 13374 13374 IN IP4 192.168.1.50
s=Yealink
c=IN IP4 192.168.1.50
t=0 0
m=audio 11780 RTP/AVP 9 8 0 18 101
a=rtpmap:9 G722/8000
a=rtpmap:8 PCMA/8000
a=rtpmap:0 PCMU/8000
a=sendrecv

Décortiqué

Élément Rôle
INVITE sip:1001@pbx.technotrement.com SIP/2.0 méthode + URI cible + version
Via: trace du chemin parcouru — chaque proxy ajoute un Via en haut
From: / To: qui appelle (avec tag unique pour identifier l'instance) / qui est appelé
Call-ID: identifiant unique de la conversation, persiste de l'INVITE au BYE
CSeq: numéro de séquence dans le dialog (incrémenté à chaque méthode)
Contact: où renvoyer les futurs messages (typiquement IP:port directe)
Content-Type: application/sdp le body est de la SDP (Session Description Protocol)

Le body SDP (qu'on verra en détail au chapitre suivant) annonce ce qu'on sait faire : "j'écoute le RTP sur 192.168.1.50:11780, en G.722 ou G.711a/µ".

Les 6 méthodes à connaître par cœur

Méthode Sens
REGISTER "Je suis le téléphone 1001, joignable sur cette IP:port — note-le pour les futures arrivées"
INVITE "Je veux établir une session"
ACK "OK, j'ai bien reçu ta réponse à mon INVITE — on est synchros"
BYE "Je raccroche"
CANCEL "Annule mon INVITE qui n'a pas encore été décroché"
OPTIONS "T'es là ?" — keepalive / discovery

5 autres existent (NOTIFY, SUBSCRIBE, MESSAGE, INFO, REFER) — utiles pour BLF, présence, transferts, MWI. On les verra au chapitre Asterisk.

Les codes de réponse

Comme HTTP, mais avec une catégorie en plus (1xx provisoires).

Famille Sens Exemple
1xx Provisoire — "je travaille dessus" 100 Trying, 180 Ringing, 183 Session Progress
2xx Succès 200 OK
3xx Redirection 302 Moved Temporarily
4xx Erreur côté client 401 Unauthorized, 403 Forbidden, 404 Not Found, 408 Request Timeout, 486 Busy Here, 487 Request Terminated (suite à un CANCEL)
5xx Erreur côté serveur 500 Server Internal Error, 503 Service Unavailable
6xx Erreur globale 603 Decline (tous les UAs ont rejeté)

Piège fréquent : un 486 Busy Here arrive quand le téléphone est en Do-Not-Disturb ou occupé. Si vous voyez ça mais que le téléphone vous semble libre, vérifiez le DND côté Yealink ou le device state côté Asterisk.

Les 3 mécanismes structurants

1. Transaction

Une transaction = une requête + toutes ses réponses (1xx, 2xx, 3xx, 4xx, 5xx, 6xx).

Identifiée par le branch dans le header Via: (le z9hG4bK-...).

Une transaction INVITE peut être : - Provisoire (1xx) : 100 Trying puis 180 Ringing - Finale (2xx-6xx) : 200 OK ou 486 Busy Here

L'INVITE est la seule méthode qui exige un ACK explicite après une 2xx finale (les autres méthodes considèrent la transaction terminée à la réponse finale).

2. Dialog

Un dialog = un INVITE accepté + tout ce qui suit (RE-INVITE, BYE…) jusqu'à la fin de l'appel.

Identifié par 3 valeurs combinées : - Call-ID: - tag From: - tag To:

Si vous voyez deux INVITE avec le même Call-ID: mais des tags différents, c'est probablement un fork (l'appel a été dupliqué vers plusieurs destinations).

3. Registration

Le téléphone IP envoie périodiquement un REGISTER au serveur SIP avec son Contact (IP:port). Le serveur stocke cette association : "extension 1001 est joignable sur 192.168.1.50:5060".

Quand quelqu'un appelle 1001, le serveur regarde son registre et envoie l'INVITE à 192.168.1.50:5060.

Durée typique du REGISTER : 3600s par défaut, mais souvent réduite à 60-300s quand le téléphone est derrière un NAT (pour maintenir la table NAT du routeur active — sinon le routeur "oublie" la mapping et le téléphone devient inatteignable).

Si un téléphone ne sonne pas : 1ère vérification = pjsip show contacts côté Asterisk. Si pas de Contact pour cette extension, il n'y a pas de REGISTER actif → SIP signaling ne peut pas atteindre le téléphone.

Le flow complet d'un appel — exemple commenté

Téléphone A (1002)              Asterisk                Téléphone B (1001)

  ────── REGISTER ─────────────►  
                              ◄── 401 Unauthorized (challenge auth)
  ────── REGISTER (auth) ──────►  
                              ◄── 200 OK (registered)

[A appelle 1001]
  ────── INVITE 1001 ──────────►  
                              ────── INVITE 1001 ─────────►
                                              ◄────────── 100 Trying
                                              ◄────────── 180 Ringing
                              ◄────────── 180 Ringing
  ◄── 180 Ringing ─────────────  
[B décroche]
                                              ◄────────── 200 OK + SDP
                              ◄────────── 200 OK + SDP
  ◄── 200 OK + SDP ────────────  
  ────── ACK ──────────────────►  
                              ────── ACK ────────────────►

  ═══════════════ RTP audio bidirectionnel ═══════════════

[A raccroche]
  ────── BYE ──────────────────►  
                              ────── BYE ────────────────►
                                              ◄────────── 200 OK
                              ◄────────── 200 OK
  ◄── 200 OK ──────────────────  

Notez : - Le 100 Trying n'est pas remonté à A — il est consommé par Asterisk (chaque hop génère son propre 100 Trying à destination du précédent). - Le 180 Ringing fait sonner A (rétroaction visuelle/auditive : "ça sonne chez le destinataire"). - L'ACK de A vers Asterisk part en parallèle de l'ACK Asterisk vers B — la 2xx finale est la seule réponse SIP qui se chevauche avec son ACK.

RE-INVITE et la mid-dialog

Une fois en appel, on peut renégocier le média (passer de l'audio à audio+vidéo, changer de codec, mettre en attente). Cela passe par un RE-INVITE : un INVITE dans le même dialog (mêmes tags From/To, même Call-ID), avec un nouveau SDP.

C'est aussi RE-INVITE qui permet le hold : - Pour mettre en attente : RE-INVITE avec a=sendonly (ou a=inactive) - Pour reprendre : RE-INVITE avec a=sendrecv

OPTIONS — le keepalive

OPTIONS est une méthode de découverte. Asterisk l'envoie périodiquement aux endpoints (typiquement chaque 30-60s) pour vérifier qu'ils sont toujours joignables.

Côté FreePBX/PJSIP, le paramètre est qualify_frequency sur l'AOR. Si l'endpoint ne répond plus à OPTIONS pendant N secondes consécutives, il est marqué Unreachablepjsip show contacts vous montre ce statut.

Astuce diag : asterisk -rx 'pjsip send qualify <endpoint>' force un OPTIONS immédiat — utile pour diagnostiquer un endpoint flaky sans attendre le prochain cycle.

Les pièges classiques

Le tag To absent dans la 1xx

Une 1xx provisoire peut être envoyée sans tag To si elle n'est pas "reliable" (1xx classique, sans Require: 100rel). Une 1xx avec tag To établit un "early dialog" — utilisé pour l'envoi d'audio early media (183 Session Progress).

Le retransmit INVITE en UDP

UDP ne garantit rien. Un client SIP retransmet automatiquement un INVITE si pas de réponse en T1 secondes (T1 = 500ms par défaut), avec backoff exponentiel. Au bout de 32s sans réponse → timeout, l'appel échoue.

Si vous voyez 3+ INVITE identiques dans un trace, c'est probablement un retransmit. Le serveur n'a peut-être pas répondu à temps.

Le mismatch Contact / Via

Si le Contact: du téléphone IP a une adresse RFC1918 (192.168.x.y) et que vous êtes en cloud, Asterisk va envoyer ses futurs messages à 192.168.x.y... qui n'est pas routable depuis Asterisk. C'est tout le problème du NAT en SIP — voir le chapitre dédié.

Lire un trace en production

Côté FreePBX/Asterisk, activer le SIP logger :

asterisk -rx 'pjsip set logger on'

Tous les messages SIP envoyés/reçus apparaîtront dans /var/log/asterisk/full.

Filtre utile en live :

tail -f /var/log/asterisk/full | grep -E '(INVITE|BYE|REGISTER|<-->|<---|--->|Call-ID:)'

Ou mieux, capture pcap pour Wireshark :

tcpdump -i any -nn -s0 -w /tmp/sip.pcap port 5060 or port 5061

Wireshark sait afficher en mode VoIP Calls (menu Telephony → VoIP Calls) et permet de "Play stream" sur un appel pour écouter le RTP — pratique pour diagnostiquer la qualité audio.

À retenir absolument

  • SIP = signal, RTP = média. Toujours raisonner couche par couche.
  • INVITE / 100 / 180 / 200 / ACK / BYE / 200 = la grammaire de base.
  • Call-ID identifie une conversation, les tags identifient les instances dans le dialog.
  • REGISTER → pjsip show contacts côté serveur. Pas de Contact = pas d'arrivée d'appel.
  • Activer le logger PJSIP à la moindre suspicion de problème de signalisation.

Pour aller plus loin

  • RFC 3261 (SIP base) — la lecture de référence, ~250 pages, ne pas tout lire d'un coup mais y revenir
  • RFC 3264 (offer/answer SDP) — pour comprendre la négociation média
  • RFC 3265 (SIP-Specific Event Notification) — pour BLF / présence
  • RFC 5626 (NAT traversal: outbound) — extension utile en mobile

Suivant : RTP et SDP