Background
The material was originally prepared as a report for asterconf 2020 . Now I will try to describe everything in more detail in this article.
MIKOPBX is a free open source PBX based on Asterisk 16 . A year ago, we took up the transition to PJSIP.
![](https://habrastorage.org/getpro/habr/upload_files/fc5/b51/255/fc5b51255f77703a7c83f66848a1c981.png)
Main reasons:
PJSIP supports " multiple registration ". You can easily register multiple end UACs on one account
Correct operation of incoming routing when setting up registration of multiple provider accounts on one address ( IP + PORT )
PJSIP is more flexible in configuration
chan_sip is not evolving and is deprecated in Asterisk 17
Next, I will describe what difficulties we encountered and what benefits we received.
The main reason is the need to support " multiple registration ". It is extremely convenient to connect several softphones / phones to your account and do not worry, an incoming call will arrive wherever you are.
Personally, I have the following devices connected:
Hardware phone on desktop in office
Softphone on laptop
Softphone on smartphone
When an incoming call arrives at the extension, all devices ring simultaneously.
?
sip.conf. , ( pjsip.conf ).
asterisk. :
contrib/scripts/sip_to_pjsip/sip_to_pjsip.py
:
Usage: sip_to_pjsip.py [options] [input-file [output-file]]
Converts the chan_sip configuration input-file to the chan_pjsip output-file.
The input-file defaults to 'sip.conf'.
The output-file defaults to 'pjsip.conf'.
.
, ( endpoint).
Asterisk contact.
"max_contacts" , endpoint.
;pjsip.conf
[226]
type = aor
max_contacts = 5
CLI Asterisk:
mikopbx*CLI> pjsip show contacts
Contact: <Aor/ContactUri..............................> <Hash....> <Status> <RTT(ms)..>
==========================================================================================
Contact: 201/sip:201@172.16.156.1:60616;ob 418d36496b Avail 3.793
Contact: 201/sip:201@172.16.156.1:60616;ob ba56853d54 Avail 2.189
Contact: 203/sip:203@172.16.156.1:60616;ob 2cd641799f Avail 0.988
Objects found: 3
, , dialplan.
c :
;extensions.conf
[internal-users]
; 3
; PJSIP_DIAL_CONTACTS - Dial-
; &
; ID endpoint
exten => _XXX,1,Set(dialContacts=${PJSIP_DIAL_CONTACTS(${EXTEN})})
; Dial
; "dialContacts"
; , endpoint
same => n,ExecIf($["${dialContacts}x" != "x"]?Dial(${DC},,Tt))
dialplan .
. , , asterisk " " " ". , .
SIP PJSIP SIP "PBX - UAC".
INVITE = SIP/104-0000XX.
endpoint , INVITE , .
, :
, AMI
dialplan
CDR
, , , :
CTI , AMI
. Paging. Intercom
. "". , .
UAC . " " INVITE . :
Call-Info:\;answer-after=0
, .
chan_sip originate SIPADDHEADER:
Action: Originate
Channel: SIP/104
Context: from-internal
Exten: 74952293042
Priority: 1
Callerid: 104
Variable: SIPADDHEADER="Call-Info:\;answer-after=0"
chan_sip. INVITE.
PJSIP . extensions.conf:
[internal-users]
exten => 204,1,Dial(${PJSIP_DIAL_CONTACTS(204)},,Ttb(dial_create_chan,s,1)))
[dial_create_chan]
exten => s,1,Set(PJSIP_HEADER(add,Call-Info)=\;answer-after=0)
same => n,return
"b" "Dial" Gosub "dial_create_chan".
SIP INVITE.
: "dial_create_chan" - dialplan, , SIP .
:
[internal-users]
; :
exten => _XXX,1,Set(d=${PJSIP_DIAL_CONTACTS(${EXTEN})})
; :
same => n,ExecIf($["${FIELDQTY(d,&)}"!="1"]?Set(__SIPADDHEADER=${EMPTY}))
same => n,ExecIf($["${d}x" != "x"]?Dial(${DC},,Ttb(dial_create_chan,s,1)))
[dial_create_chan]
exten => s,1,ExecIf($["${SIPADDHEADER}x" == "x"]?return)
same => n,Set(header=${CUT(SIPADDHEADER,:,1)})
same => n,Set(value=${CUT(SIPADDHEADER,:,2)})
same => n,Set(PJSIP_HEADER(add,${header})=${value})
same => n,Set(__SIPADDHEADER=${EMPTY})
same => n,return
"FIELDQTY" , endpoint. , , , .
"CUT" "SIPADDHEADER", .
, PJSIP_HEADER SIPADDHEADER. "" .
UserAgent
SIP endpoint. pjsip . :
[get-user-agent]
exten => 300,1,NoOp(--- Incoming call ---)
same => n,Set(vContact=${PJSIP_AOR(300,contact)})
same => n,Set(vUserAgent=${PJSIP_CONTACT(${vContact},user_agent)})
same => n,NoOp(--- ${vContact} & ${vUserAgent} ---)
... ... ...
same => n,Hangup()
AOR ID 300. ID endpoint = ID AOR = EXTEN:
; ${PJSIP_CONTACT(${PJSIP_AOR(${EXTEN},contact)},user_agent)}
"PJSIP_AOR" ID AOR, , "contact".
"PJSIP_CONTACT" , , "user_agent".
, PJSIP_AOR(300,contact) ID , , CLI.
PJSIP_AOR:
201;@e758f5661420b391e239386a94edbefe
CLI:
pjsip show contacts 201/sip:201@172.16.156.1:57130;ob
Contact: 201/sip:201@172.16.156.1:57130;ob
Asterisk, :
(temporary)
No Response
408 Request Timeout
500 Internal Server Error
502 Bad Gateway
503 Service Unavailable
504 Server Timeout
6xx
(Permanent)
401 Unauthorized
403 Forbidden
407 Proxy Authentication Required
4xx, 5xx, 6xx
pjsip.conf :
[74952293042]
type = registration
;
;
retry_interval = 30
;
max_retries = 100
; ""
; 403 Forbidden .
forbidden_retry_interval = 300
; Fatal (non-temporary 4xx, 5xx, 6xx)
fatal_retry_interval = 300
sip_to_pjsip.py , .
:
sip.test.ru
sip.test.ru 10.10.10.10
11.11.11.11
10.10.10.10
.
PJSIP IP :
[74952293042]
type = identify
; ... ... ...
match=sip.test.ru,185.45.152.0/24,185.45.155.0/24;
; ... ... ...
"match", , IP . endpoint.
, "endpoint_identifier_order".
:
endpoint_identifier_order=ip,username,anonymous
, IP:PORT, :
endpoint_identifier_order=username,ip,anonymous
, :
99999 - 10.10.10.10:5060
88888 - 10.10.10.10:5060
77777 - 10.10.10.10:5060
"endpoint_identifier_order", :
endpoint ( IP:PORT), endpoint "99999" .
, endpoint, PJSIP/99999-0000XXX,
SIP URI
.
"res_pjsip_endpoint_identifier_anonymous.so".
pjsip.conf
[anonymous]
type = endpoint
allow = alaw
timers = no
context = public-direct-dial
extensions.conf
[public-direct-dial]
exten => 74952293042,NoOp(--- Incoming call to ${EXTEN} ---)
same => n,Dial(PJSIP/204,,TKg));
same => n,Hangup()
public-direct-dial dialplan.
exten DID .
PJSIP . chan_pjsip ,
PJSIP
PJSIP ,
chan_pjsip ,
The disadvantages of switching to chan_pjsip are:
Dialplan upgrade required
Changing AMI behavior, which affects CTI clients
CDR behavior is changing, call history doping needs to be improved
chan_pjsip is under active development, there are gross bugs in recent asterisk releases. do not chase new versions, it is better to wait for the appearance of "certified" versions