How to Make an iOS VoIP App With Pjsip: Part 1

In this tutorial series, I will walk you through creating an iOS VoIP app. After finishing this series, you’ll have a working VoIP app, that can make outbound VoIP call and receive incoming call. 

To achieve this, we’re going to utilize an open source library – pjsip.

Prerequisite and Environment

To follow this tutorial, you should know the basics of developing an iOS app. Also, you should be comfortable with shell, since we’ll execute shell commands to do the compiling of pjsip

For the environment, we’re using:

  • OS X Mavericks 10.9
  • Xcode 5.1.1
  • Pjsip 2.2.1

(This article was written on 2014 and posted on my old blog. Most of the content should still work on latest Mac and iOS, i.e, macOS Sierra and Xcode 8.3. Please let me know if you find anything not working, thanks.)

What’s pjsip

In its official website, we can see the definition of pjsip:

PJSIP is a free and open source multimedia communication library written in C language implementing standard based protocols such as SIP, SDP, RTP, STUN, TURN, and ICE. It combines signaling protocol (SIP) with rich multimedia framework and NAT traversal functionality into high level API that is portable and suitable for almost any type of systems ranging from desktops, embedded systems, to mobile handsets.

Wow, so many terms. Terrifying, isn’t it? And it does takes a lot of time and effort to understand all of them. Fourtunately, for now, we only need to pay attention to the single most important one here: SIP.

SIP(Session Initiation Protocol), as its name implies, is the protocol to initiate a session. We use SIP, to prepare and initiate, or receive VoIP calls.

For example, a client sends a sip message – REGISTER – to register itself on the server, and sends an INVITE message to initiate a call.

Pjsip implemented SIP and many other protocols needed to support VoIP calling. By using pjsip, we could easily create a VoIP app.

Compiling pjsip for iOS

First of all, you need to download the pjsip library. And this is the official link.

Pjsip supports multiple platforms: Windows, Mac, Linux, iOS, Android, etc. In order to use it in our iOS project, we need to compile pjsip specifically for iOS platform.

You could simply follow the following steps to compile it for iOS, or check out the official tutorial for further details.

Configure pjsip to target iOS platform

To specify the target platform is iOS, we need to create a file: pjlib/include/pj/config_site.h, and set it’s content as:


The 1st line tells pjsip to target the iOS platform, and the 2nd line includes some basic settings from the sample configuration file.

Actually compile the pjsip library

This is very standard and natural, just use the following command to actually compile it:

$ ./configure-iphone && make dep && make clean && make

Specifying armv7s or arm64 as architecture

By default, the target architecture is armv7. This architecture is available for iPhone since iPhone 3GS, and all iPad.

However, besides this, for iPhone 5, iPhone 5c, and iPad 4, we have armv7s. And for iPhone 5s and iPad air, we have arm64.

If you want to get the max out of the device, you could specify the specific architecture by setting the ARCH variable. For example:

$ ARCH='-arch armv7s' ./configure-iphone && make dep && make clean && make


$ ARCH='-arch arm64' ./configure-iphone && make dep && make clean && make

Undefined symbols for architecture armv7s

If you compile for a different architecture after a previous one, you may get an error like this:

Undefined symbols for architecture armv7s:
"_main", referenced from:
implicit entry/start for main executable
ld: symbol(s) not found for architecture armv7s
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[3]: *** [../bin/samples/arm-apple-darwin9/pjsua2_demo] Error 1
make[2]: *** [pjsua2_demo] Error 2
make[1]: *** [samples] Error 2
make: *** [all] Error 1

This is caused by a bug of the Makefile, the make clean statement failed to remove this file:


So, to fix this issue, just simply run

$ make clean
$ rm pjsip-apps/build/output/pjsua2_sample-arm-apple-darwin9/pjsua2_demo.o

And then, go ahead and run the compile command.

The compilation result

After compiling, the pjsip binary libraries are located in:


The compiling command also compiles some third party libs being used by pjsip. These third party libraries are located in:


In order to use the pjsip libraries, we need to include the corresponding header files. Naturally, the header files are located in:


Run the testing project

Pjsip already contains an iOS project that you could build and run. Simply open pjsip-apps/src/pjsua/ios/ipjsua.xcodeproj in your Xcode, and do the following steps, you’ll be able to get a running pjsip app immediately.

Configure the bundle identifier

We need to configure the Bundle Identifier in order to run it on our own devices.

  • We could do this by configure the Bundle Identifier in the “General” settings panel.
  • Alternatively, we could also edit the Bundle identifier field in ipjsua/Supporting Files/ipjsua-Info.plist.

For iPhone 5 or later

If you are testing on iPhone 5 or later, and you didn’t specify the ARCH variable during compiling, you may get an error similar to the following:

No architectures to compile for (ONLY_ACTIVE_ARCH=YES, active arch=armv7s, VALID_ARCHS=armv7).

In order to solve it, just turn off the ONLY_ACTIVE_ARCH flag. Open the Build Settings, and change the “Build Active Architecutre Only” flag from YES to NO.

Please note that, if you’re using iPhone 5s, and set the ARCH to arm64, you might get an compilation error of:

Implicit declaration of function 'showNotification' is invalid in C99   

To make the compiler happy, just add this line of code before the on_incoming_call function:

pj_bool_t showNotification(pjsua_call_id call_id);

Library not found for -lmilenage-arm-apple-darwin9

According to this ticket, milenage is only used in very rare scenarios. So by default, this library is not compiled.

To solve it, you could:

  • simply remove this linking requirement. Go to the “Build Phases” tab, and remove the “libmilenage-arm-apple-darwin9.a” from the Link Binary With Libraries section.
  • Or, manually compile it by executing make in folder third_party/build/milenage

Actually run it in your device.

Great, everything is done, you can now compile and run it on your own device!

When the app launched, you’ll see the pjsua logo and a message like:

Telnet to

You could now connect to the app via Telnet, and send PJSUA-CLI commands to register account, make call, send SMS, etc.

To be continued…

One thought on “How to Make an iOS VoIP App With Pjsip: Part 1

  1. Hello , Thanks for the tutorial over SIP>

    After performing part 1 instruction I have received below error . Can you please help me out to resolve this.

    Showing Recent Issues
    “_pjsip_register_method”, referenced from:
    _default_mod_on_rx_request in pjsua_app.o

    “_pjsip_ack_method”, referenced from:
    _default_mod_on_rx_request in pjsua_app.o

    “_pj_pool_safe_release”, referenced from:
    _app_destroy in pjsua_app.o

    “_pjsip_msg_find_hdr”, referenced from:
    _simple_registrar in pjsua_app.o

    “_pjsip_endpt_get_capability”, referenced from:
    _default_mod_on_rx_request in pjsua_app.o

    “_pjsip_generic_string_hdr_create”, referenced from:
    _default_mod_on_rx_request in pjsua_app.o
    _simple_registrar in pjsua_app.o



Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s