Asterisk 12 Part IV: The SIP Stack of the Future

By Matt Jordan

Hello again! Last time, we looked at Asterisk 12. Since then, a lot has happened – namely, AstriCon!  You may have read just a little bit about AstriCon on this blog, but what you may not have read about were the major events that occurred in conjunction with AstriCon.

The first was the annual AstriDevCon meeting, in which numerous developers and power users in the Asterisk community met and discussed Asterisk 12 and the roadmap for the next major version of Asterisk. The response to the new SIP stack and the APIs was overwhelmingly positive, and a lot of features and ideas that were built on the new SIP stack, architecture, and APIs were mapped out during that meeting.

The second event that occurred in conjunction with AstriCon was the first beta release of Asterisk 12. This release signified an advancement in the readiness of Asterisk 12 for more general use.  As we mentioned in previous blog posts, due to the numerous architectural improvements, Asterisk 12 contains more changes than previous Asterisk releases and is thus undergoing two test release cycles. People looking to test out Asterisk 12 should, of course, read up on all of the changes before deploying it.

With all of that said, today we’ll be looking at the new SIP stack in Asterisk 12, based on Teluu’s PJSIP stack, with a focus on the design and architecture of the new stack and what it means for the future of Asterisk.

Motivation

The legacy SIP channel driver in Asterisk was created roughly ten years ago, in 2002.  At the time, SIP was a relatively new standard with RFC 3261 having only been released in June of that year. At the time, no one could have fully predicted the dominance that SIP would eventually play in the VoIP market or the rapid expansion of RFCs and standards that would follow. The SIP channel driver implementation in Asterisk was done in a single channel driver module called chan_sip.  Because the full scope of what would encompass “SIP” was not known at the time, by 2012 the design of chan_sip had reached a point where its structure was no longer able to keep pace with the expansion in technology.  At AstriDevCon 2012, the developer community felt that an alternative was needed.

So, motivated by chan_sip’s limitations, we set out to design a new set of modules that would not only provide the SIP functionality Asterisk needs today, but would be flexible and tolerant to changing requirements in the future. The result is the PJSIP stack in Asterisk, which is still a channel driver, but also a lot more.

Design

 One of the first decisions that influenced the design philosophy for the new SIP functionality in Asterisk was to implement that functionality as a stack provided by a suite of loadable modules instead of a single channel driver module. This means that while there is a PJSIP channel driver in Asterisk 12 – aptly named chan_pjsip – its purpose is to bridge between the PJSIP stack and the actual PJSIP channel executing dialplan in Asterisk. The PJSIP stack itself consists of a host of other modules, each of which provides a different piece of functionality that the channel driver and other modules can use. This approach has several benefits:

  1. Implementation of functionality within the PJSIP stack is isolated, making it easier to enhance, maintain, and even replace!  For example, the code that handles media negotiation and setting up calls is in a separate dynamically loadable module from the code that handles MWI subscriptions and notifications.  Separating this logic, which follows well known software design best practices, also has the added benefit of letting a user customize their installation by only loading the modules that provide the functionality that they need.
  2. Developing new functionality for the PJSIP stack is substantially easier than it was for the chan_sip channel driver. The PJSIP stack in Asterisk today has modules that provide frameworks that subsequent modules can consume to provide end-user features. As an example, a single module, res_pjsip_pubsub, provides a publish/subscribe framework that other modules use to provide event notification features. This includes features such as MWI, provided by res_pjsip_mwi, and device state, provided by res_pjsip_exten_state. The fact that the implementation of such features can be done in separate modules means that developers who want to enhance Asterisk with new functionality, such as adding new event packages, can do so in a manner that not only minimizes the portion of the stack that they interface with but also minimizes the impact to existing systems.

A high level view of the modular architecture of the PJSIP stack in Asterisk 12 is shown below. Note that this does not show all of the modules currently available in the PJSIP stack; rather, it shows the functionality provided by a small selection of the most commonly used modules.

Configuration

 Configuration for the new PJSIP stack uses a very different schema than the historical SIP channel driver. Rather than lump all configuration for a device into a peer/user/friend (which does not have a strong relationship to SIP concepts), the new stack takes the approach of breaking up configuration into logical sections so that there are different sections for different purposes.  For example, there are sections for configuring how a SIP endpoint authenticates and how it identifies itself, as well as the media and other behavioral properties that are allowed on the endpoint.

As an example, in sip.conf a SIP peer might have looked something like this:

[my_phone]
type = peer
context = local_office
disallow = all
allow = ulaw
host = dynamic
secret = super_secret
qualify = yes
dtmfmode = rfc2833

This peer definition mixes basic properties of the device, such as the codecs that are allowed, along with authentication and registration behavior. While this has some benefits in that a single peer can be quickly defined, this approach encounters drawbacks when attempting to define disparate shared attributes among multiple devices. It has also historically forced a rather large schema for real time database integrations, which is not always ideal.

The PJSIP configuration for this endpoint would look like the following:

[my_phone_auth]
type = auth
auth_type = userpass
username = my_phone
password = super_secret

[my_phone_aors]
type = aor
max_contacts = 10
qualify_frequency = 300

[my_phone_endpoint]
type = endpoint
auth = my_phone_auth
aors = my_phone_aors
disallow = all
allow = ulaw
context = local_office
dtmfmode = rfc4733 

While the definition of all of these options is beyond the scope of this blog post (and is available on the Asterisk wiki and via the CLI command ‘config show help’), you can see that there are different sections that make up the full definition of the SIP endpoint. Not only does this allow a user to make greater use of templates in the configuration of endpoints, it also more cleanly maps back to a real time database that stores this data.

More information on how to configure PJSIP can be found on the Asterisk wiki:

State of PJSIP in Asterisk 12

The first goal for PJSIP in Asterisk 12 was to strive for feature parity with the existing SIP channel driver.  While we did not quite reach full feature parity, the PJSIP stack is feature rich and suitable for many deployment scenarios. Some of the features available in Asterisk 12 are:

  • Calls/media sessions
    • Media streams (audio/video), including media format attribute negotiation and support for all Asterisk formats/codecs
    • Caller ID/Connected Line/Redirecting/Forwarding information
    • DTMF (inband, RTP, and INFO request)
    • Session Timers
    • PRACK/100rel
    • Reason header
    • Multiple transports (UDP, TCP, TLS, and WS)
    • Secure media (SDES-SRTP and DTLS-SRTP)
  • Digest authentication
  • Transfers
    • INVITE with Replaces
    • Refer handling with NOTIFY request support
  • INFO requests
    • Video refresh/fast picture update
    • One touch recording
  • Messaging – out of call/in call text MESSAGE request integration
  • Integration with Asterisk’s SIP Security Framework
  • Registration/Registrar, including allowing multiple device registrations to a single endpoint
  • Qualify support using OPTIONS requests
  • CLI/AMI initiated NOTIFY requests with configurable event packages
  • SIP header manipulation – SIP_HEADER function (add, update, and remove SIP headers)
  • Trace logging
  • Publish/subscribe handling
    • MWI event package
    • Extension/device state (PIDF, XPIDF, and CPIM-PIDF)

There are some features that chan_sip provides that did not make the first cut.  However, due to the release policy enacted for Asterisk 12, we fully expect that many of these features will be introduced in Asterisk 12 as time goes on.  In addition, many AMI and CLI commands are currently being implemented by members of the Asterisk developer community, and new functionality is being added on a continuing basis. Expect the PJSIP feature list to grow considerably in the months to come!

The Future of SIP in Asterisk

We in the Asterisk developer community have spent a significant amount of time and effort testing PJSIP for the Asterisk 12 beta. However, that does not mean that the work is finished. We will need all members of the Asterisk community to test the new PJSIP channel driver and all of the various modules that provide SIP functionality. As you test and start to deploy PJSIP, feedback is welcomed on the asterisk-dev mailing list.

We are fully confident that the new PJSIP stack is the best path forward for SIP in Asterisk. Working together, the Asterisk community can help make PJSIP a successful reality as the provider of SIP functionality for the future of Asterisk.

Related Posts

There Are 7 Comments

  • Gahz says:

    Please write more and more about Asterisk 12. 🙂

  • Uri says:

    Well done.

    one issue i have a problem with….
    I am using DIAL(PJSIP/${EXTEN} to set a call to a new callee.
    I need the SIP callid of this call.
    It seems to be that there is no option to retrieve the callid in PJSIP… is there?

  • Matt Jordan says:

    My initial reply was that there isn’t way to currently extract the Call-ID value – but I was wrong!

    I forgot about the very handy PJSIP_HEADER function, which lets you extract SIP headers from a channel – as well as add/update/remove custom headers. With it, you should be able to get the SIP Call-ID header from a PJSIP channel.

  • Stomaz says:

    Congratulations!
    This is a very good notice for everyone!
    I’m testing asterisk-13.0.1 with new features and WebRTC!
    Asterisk rocking the future of telephony!!

    Best!!

  • Youssef says:

    Hi,

    Can you tell me what’s the difference between Chan and PJSIP ?

  • Jacques Wheeler says:

    I like to see what codec’s are being used on a current call.
    on chan_sip i can go to reports and channel but on my pjsip asterisk if i go there i can only see the call that are in progress and no codec

    is there a way in pjsip asterisk to view this info

  • I don’t know what reports you’re talking about, but showing the channel information for a channel, e.g. “core show channel PJSIP/xyz” or “core show channel SIP/xyz” both show the native formats, the read format, and the write transcode format (if applicable).

Add to the Discussion

Your email address will not be published. Required fields are marked *

About the Author

Matt Jordan

Matt Jordan joined Digium in July of 2011. Since joining Digium, he has served as lead on the Asterisk open source project, as an Engineering Manager, and as Director of Technology. In June 2016, Jordan was named CTO of Digium. In this role, Jordan is responsible for technology and architectural decisions used in the Company’s product and service offerings. Jordan holds a Bachelor of Science degree in Computer Engineering from Michigan Technological University, and a Master of Science degree in Electrical Engineering from Louisiana State University and multiple patents.

See All of Matt's Articles