Телефонный звонок может быть завершен по разным причинам — как зависящим от абонента (занят, не отвечает, неверный номер), так и нет (перегрузка канала, например).
Asterisk используется в системах, где часто используются различные протоколы связи между станциями и абонентскими устройствами, и по всей этой цепочке нам важно передавать корректные коды завершения звонка. К сожалению эта тема слабо документирована, и самой лучшей документацией на эту тему оказались исходники собственно Asterisk :)
Внутри Asterisk используется набор кодов завершения звонка, сделанный на основе Q.931, он сильно отличается от кодов в SIP, и поэтому согласно RFC 3398 есть правила трансляции. К сожалению эти правила неоднозначны — то есть после цепочки преобразований SIP<->Q.931<->SIP мы не обязательно получим тот же код, ибо набор кодов в Q.931 во-первых больше чем в SIP, а во-вторых не все коды из SIP могут быть однозначно отражены в события Q.931.
Использование hangup cause codes в Asterisk
В старых версиях Asterisk для завершения звонка с указанием конкретного cause code использовалась переменная PRI_CAUSE. Поддерживалась она только в chan_zaptel и chan_misdn.
Начиная с версии 1.4 для этого используется параметр команды Hangup. Это выглядит, например, так:
exten => someextension,n,Hangup(17)
Несмотря на то, что это нигде не документировано — указываться код может не только в виде числа, но и в виде строки:
exten => someextension,n,Hangup(USER_BUSY)
Также команда Dial в переменной HANGUPCAUSE возвращает код завершения звонка, который, кстати, рекомендуется добавлять в CDR (к сожалению сам Asterisk этого не делает).
При этом в chan_sip реализовано преобразование кода завершения звонка согласно RFC 3398. Для этого есть две таблицы — по одной из SIP кода мы получаем Q.931, по другой — наоборот. При этом, как я уже говорил, полноценное преобразование в обе стороны возможно только для ограниченного количества вариантов. Для частичного решения этой проблемы, астериск также добавляет в сообщение BYE заголовк X-Asterisk-HangupCauseCode.