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 :
- Votre téléphone envoie un message SIP "INVITE" au serveur
- Le serveur le route vers le téléphone destinataire
- Le destinataire répond "200 OK"
- Votre téléphone confirme avec "ACK"
- À ce moment, l'audio (RTP) commence à circuler — directement entre les deux téléphones, généralement, sans passer par le serveur.
- 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 Herearrive 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 ledevice statecô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 contactscô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é Unreachable — pjsip 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 :
Tous les messages SIP envoyés/reçus apparaîtront dans /var/log/asterisk/full.
Filtre utile en live :
Ou mieux, capture pcap pour Wireshark :
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-IDidentifie une conversation, les tags identifient les instances dans le dialog.- REGISTER →
pjsip show contactscô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