Xianwen's blog

Life is either a daring adverventure, or nothing.

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

Good day! And welcome to the 4th part of this tutorial series!

We have successfully compiled pjsip and the demo in part 1, managed to set up the VoIP server in part 2, and discussed the basic usage of pjsip APIs in part 3.

In this part 4, we will start building our own iOS VoIP app from stratch. By setting up a new project to make use of the pjsip libraries and header files, we’ll have a good foundation project in which we can call any pjsip methods.

You could download the source code of this project on Github here. Each commit of the project, is representing one step of this tutorial.

Creating new project

Let’s start by creating a Single View Application

And name it as simpleVoIP

Using pjsip and the architecture problem

Normally, using pjsip is a very tedious and error prone procedure. You need to:

  1. Compile pjsip for different architectures: armv7, armv7s, arm64, and i386 (for the detail of how to do this, you can check out the 1st tutorial)
  2. Use the corresponding static libraries in your project based on your target platform: armv7 for iPhone 4, armv7s for iPhone 5, arm64 for iPhone 5s, and i386 for simulator.

In fact, what you’ll get after compiling pjsip, is not a single static library, but a set of static libraries. For example, in this tutorial, we’ll use the following libraries (these are the same libraries being used in the pjsip built-in demo):

Pjsip libraries:

  • pjlib/lib/libpj-arm-apple-darwin9.a
  • pjlib-util/lib/libpjlib-util-arm-apple-darwin9.a
  • pjmedia/lib/libpjmedia-arm-apple-darwin9.a
  • pjmedia/lib/libpjmedia-audiodev-arm-apple-darwin9.a
  • pjmedia/lib/libpjmedia-codec-arm-apple-darwin9.a
  • pjnath/lib/libpjnath-arm-apple-darwin9.a
  • pjsip/lib/libpjsip-ua-arm-apple-darwin9.a
  • pjsip/lib/libpjsip-arm-apple-darwin9.a
  • pjsip/lib/libpjsip-simple-arm-apple-darwin9.a
  • pjsip/lib/libpjsua-arm-apple-darwin9.a

Third party libraries:

  • third_party/lib/libg7221codec-arm-apple-darwin9.a
  • third_party/lib/libgsmcodec-arm-apple-darwin9.a
  • third_party/lib/libilbccodec-arm-apple-darwin9.a
  • third_party/lib/libresample-arm-apple-darwin9.a
  • third_party/lib/libspeex-arm-apple-darwin9.a
  • third_party/lib/libsrtp-arm-apple-darwin9.a

So, if we want to switch between simulator and real device during testing, we’ll have to change this whole set of libraries being used.

For example, when we switch to simulator, we’ll need to link something like i386/libpj-arm-apple-darwin9.a, i386/libpjlib-util-arm-apple-darwin9.a, etc. (assuming i386 is the folder containing i386 pjsip libraries); and when we switch to real device, we’ll need to change them to armv7/libpj-arm-apple-darwin9.a, armv7/libpjlib-util-arm-apple-darwin9.a, etc. instead.

This is very annoying, tedious, and error prone. So let’s introduce fat libraries to help us with this problem.

Fat library

A fat library is a library that integrate libraries of different architectures into one single libary. This way, we don’t need to switch between different libraries when we change the target device/platform.

To create a fat library, you can use the following command:

$ export LIB_NAME="libg7221codec-arm-apple-darwin9.a"
$ lipo -arch armv7 armv7/$LIB_NAME -arch armv7s armv7s/$LIB_NAME -arch arm64 arm64/$LIB_NAME -arch i386 i386/$LIB_NAME -create -output unified/$LIB_NAME

This command integrates the armv7, armv7s, arm64 and i386 libraries into a single fat library. You could use the lipo command to look into the result:

$ lipo -info unified/libg7221codec-arm-apple-darwin9.a
Architectures in the fat file: unified/libg7221codec-arm-apple-darwin9.a are: armv7 armv7s i386 arm64

I strongly recommend you to try building your own fat libraries, so that you will be more familiar with this whole process. But if you just want to start working on your iOS VoIP app right away, you could download the fat library I built here.

Adding the libraries into the project

After the previous step, adding the libraries is just a piece of cake now.

Simply drag those libxxx.a into the Frameworks group, and Xcode will automatically link them during compile. You can see that in the Build Phases tab.

The header files of pjsip

In order to use pjsip, you need to update your Header Search Path of your project, so that it can reach all the header files contained in the “include” folder of the following 5 pjsip folders:

  • pjlib/include
  • pjlib-util/include
  • pjmedia/include
  • pjnath/include
  • pjsip/include

Usually, we would create a folder that contains all of them, so that we only need to add that folder in the search path.

One way to do this, is to manually create a pjsip-include folder, and move all the files in these 5 folders into it.

Another approach, is to let pjsip do it for you: by specifying a output folder for the —prefix parameter of configure-iphone script during the compiling process. This way, all the needed header files will be included in a single “include” folder in the folder you specified.

For example, you could use the following command to compile pjsip

$ ./configure-iphone --prefix=/Users/xianwen.chen/Pjsip/pjproject-2.2.1/output/ && make dep && make && make install

After compiling, there will be two folders in the “output” folder: a “lib” folder containing all the compiled binary libraries, and a “include” folder containing all the needed header files. You can then simply use this “include” folder for all the pjsip header files.

Again, if you want to skip these steps, you can download the “pjsip-include” folder made by me directly here.

Adding the header files into the project

To use the “pjsip-include”, let’s copy this folder into the project directory. This way, our project can be successfully compiled regardless of the outer environment.

In this case, we’ll copy it to the simpleVoIP folder:

And then, we add the path of this folder into the “Header Search Paths”:

Link required frameworks

Pjsip makes use of the iOS built in frameworks, to perform tasks like using the network, audio, etc.

We need to link these required frameworks in order to run our app. In this tutorial, we’ll need three frameworks:

  • AVFoundation.framework
  • CFNetwork.framework
  • AudioToolbox.framework

Add these frameworks in the “Build Phases” tab:

Great, now you’re free to make use of any pjsip functions in this project!

To be continued…