android pjsip编译

编译系统分析java


1.configurelinux

pjsip是基于autoconf与automak的编译系统,首先用./configure 传入参数,而后传入build.mak.in,最后生成build.mak,好比,咱们用./configure --enable_shared,传入一个enable_shared参数,在aconfigure.ac中,有以下一段:android

AC_SUBST(ac_shared_libraries)git

AC_ARG_ENABLE(shared,架构

      AC_HELP_STRING([--enable-shared],app

     [Build shared libraries]),eclipse

      [if test "$enable_shared" = "yes"; thenide

[ac_shared_libraries=1]svn

CFLAGS="$CFLAGS -fPIC"ui

AC_MSG_RESULT([Building shared libraries... yes])

       fi],

      AC_MSG_RESULT([Building shared libraries... no])

      )

 

其中若是检测到了enable_shared=yes,那么就会将ac_shared_libraries=1,这个变量咱们从build.mak.in中能够看到。

 

ifeq (@ac_shared_libraries@,1)

export PJ_SHARED_LIBRARIES := 1

endif

 

它实际上是控制build.mak中是否输出PJ_SHARED_LIBRARIES这个变量,若是没有定义,那么最终build.mak中生成的是

ifeq (,1)

export PJ_SHARED_LIBRARIES := 1

endif

 

2.目标编译及rules.mak

 

若是咱们没有定义上面的enable_shared参数,那么最终咱们为每一个模块生成的,是一个静态库.a文件。顶层Makefile进入,会进入每一个模块目录下执行make

all clean dep depend print:

for dir in $(DIRS); do \

if $(MAKE) $(MAKE_FLAGS) -C $$dir $@; then \

    true; \

else \

    exit 1; \

fi; \

done

 

所以,咱们分析一个模块的编译过程就够了,以pjlib为例。

其实对于每一个模块好比pjlib,在pjlib/build目录下都有一个Makefile文件,对于每一个模块的编译流程其实都是千篇一概的,好比收集objs目标文件,创建依赖,而后编译.o,最终打包成一个静态库,从这个流程中咱们知道除了收集objs目标和一些特定的编译参数以外,其余的过程都同样,所以,这一块代码,被pjsip独立出来,放在了build/rules.mak中。咱们分析一下pjlib的makefile.

 

1.包含rules.mak,导出最终目标给rules.mak

RULES_MAK := $(PJDIR)/build/rules.mak

 

export PJLIB_LIB := libpj-$(TARGET_NAME)$(LIBEXT)

 

2.收集OBJS,定义编译选项,并所有导出,不导出rules.mak看不到哦

export PJLIB_SRCDIR = ../src/pj

export PJLIB_OBJS += $(OS_OBJS) $(M_OBJS) $(CC_OBJS) $(HOST_OBJS) \

activesock.o array.o config.o ctype.o errno.o except.o fifobuf.o \

guid.o hash.o ip_helper_generic.o list.o lock.o log.o os_time_common.o \

os_info.o pool.o pool_buf.o pool_caching.o pool_dbg.o rand.o \

rbtree.o sock_common.o sock_qos_common.o sock_qos_bsd.o \

ssl_sock_common.o ssl_sock_ossl.o ssl_sock_dump.o \

string.o timer.o types.o

export PJLIB_CFLAGS += $(_CFLAGS)

export PJLIB_CXXFLAGS += $(_CXXFLAGS)

export PJLIB_LDFLAGS += $(_LDFLAGS)

 

3.将实际编译任务交给rules.mak

$(PJLIB_LIB) $(PJLIB_SONAME):

$(MAKE) -f $(RULES_MAK) APP=PJLIB app=pjlib $(subst /,$(HOST_PSEP),$(LIBDIR)/$@)

能够看到,咱们传入了两个参数APP以及app,这就是rules.mak能够复用于编译全部模块的缘由,另外在最后咱们指定了实际的编译目标,就是$(LIBDIR)/$@

这个目标其实就是PJLIB_LIB,libpj-$(TARGET_NAME)$(LIBEXT),这个TARGET_NAME也是能够在configure指定的,能够是win32,cygw之类的,若是没有指定就是auto自动识别,在build.mak中能够看到是arm-unknown-linux-androideabi,因此对于pjlib,咱们最终生成的静态库目标是../lib/libpj-arm-unknown-linux-androideabi.a

 

4.rules.mak编译过程

ifneq ($(LIB),)

$(subst /,$(HOST_PSEP),$(LIBDIR)/$(LIB)): $(OBJDIRS) $(OBJS) $($(APP)_EXTRA_DEP)

if test ! -d $(LIBDIR); then $(subst @@,$(subst /,$(HOST_PSEP),$(LIBDIR)),$(HOST_MKDIR)); fi

$(AR) $(AR_FLAGS) $@ $(OBJS)

$(RANLIB) $@

endif

很方便就能够在里面找到,咱们实际传入的目标,里面的依赖$(objs)就是咱们导出的,所以它会自动定位到下面的编译目标。

$(OBJDIR)/%$(OBJEXT): $(SRCDIR)/%.c

$(CC) $($(APP)_CFLAGS) \

$(CC_OUT)$(subst /,$(HOST_PSEP),$@) \

$(subst /,$(HOST_PSEP),$<) 

 

编译完后最终调用AR,生成静态库。

 

 

pjsip代码很容易下,在官网用git下载就行,2.x版本已经支持video,从配置和编译上,比之前复杂多了,这里咱们下下来的最新版本是2.4

 

1.编译前配置

配置config_site.h文件,这是个啥呢,它是对本地库的自定义配置,全部的自定义配置都必须放在这个文件中,由于这个文件并不在svn仓库中,因此随便修改不用担忧在同步svn时会被冲掉。

 

这个config_site.h文件中能够复写如下文件中的宏:

· PJLIB Configuration (the pjlib/config.h file)

· PJLIB-UTIL Configuration (the pjlib-util/config.h file)

· PJNATH Configuration (the pjnath/config.h file)

· PJMEDIA Configuration (the pjmedia/config.h file)

· PJSIP Configuration (the pjsip/sip_config.h file)

 

同时,这个pjlib/include/pj/目录下已经有一个config_site_sample.h.咱们先建立,而后包含这个文件就行。

 

在config_site.h中添加android架构以及media支持。

 

#define PJ_CONFIG_ANDROID 1

#include <pj/config_site_sample.h> 

 

#define PJMEDIA_HAS_VIDEO 1

 

2.添加NDK路径支持

编译时须要用到环境变量中的NDK_PATH以及两个变量TARGET_GET和APP_PLATFORM,这里咱们直接写入到配置文件configue-android中。

NDK_PATH=$(dirname $(which ndk-build))

TARGET_ABI=armeabi-v7a

APP_PLATFORM=android-19

而后将NDK_PATH导出

export ANDROID_NDK_ROOT=${NDK_PATH}

 

固然,前提是这里咱们必需要先将ndk path配置到环境变量PATH中,在/etc/profile中配置

 

3.编译

$ cd /path/to/your/pjsip/dir
$ export ANDROID_NDK_ROOT=/path_to_android_ndk_dir 
$ ./configure-android
$ make dep && make clean && make

 

 

编译完成以后,若是咱们定义上面的enable-shared的话,会为每一个模块生成一个.a的静态库。那编译成静态库有什么意义呢,为何不默认编成动态库?由于对于Android这种系统来讲,默认编成动态库,那么Android也没法使用,由于这样的动态库是纯C库,java层是没法调用的,所以,pjsip使用了swig,自动化的为全部导出接口生成了android使用的JNI层文件,并与前面的全部静态库一块儿,编译成了android平台的动态库。

 

4.swig部分编译

咱们看一下pjsip-apps/src/swig/Makefile

若是识别为android平台,它会去java子目录执行make -C,继续看java/Makefile.

 

首先定义全局目标

all: $(LIBPJSUA2_SO) java

其中LIBPJSUA2_SO就是libpjsua2.so,首先就是要生成.so文件,这个文件的目标从哪来呢?

$(LIBPJSUA2_SO): $(OUT_DIR)/pjsua2_wrap.o

$(PJ_CXX) -shared -o $(LIBPJSUA2_SO) $(OUT_DIR)/pjsua2_wrap.o \

$(MY_CFLAGS) $(MY_LDFLAGS)

咱们能够看到它依赖于pjsua2_wrap.o(swig生成的中间接口目标),还有MY_LDFLAGS.

MY_LDFLAGS         := $(PJ_LDXXFLAGS) $(PJ_LDXXLIBS) $(MY_JNI_LDFLAGS) $(LDFLAGS)

里面包含了一个PJ_LDXXLIBS,这个定义在build.mak中,引用的变量以下

export APP_LDLIBS := $(PJSUA_LIB_LDLIB) \

$(PJSIP_UA_LDLIB) \

$(PJSIP_SIMPLE_LDLIB) \

$(PJSIP_LDLIB) \

$(PJMEDIA_CODEC_LDLIB) \

$(PJMEDIA_LDLIB) \

$(PJMEDIA_VIDEODEV_LDLIB) \

$(PJMEDIA_AUDIODEV_LDLIB) \

$(PJMEDIA_LDLIB) \

$(PJNATH_LDLIB) \

$(PJLIB_UTIL_LDLIB) \

$(APP_THIRD_PARTY_LIBS)\

$(APP_THIRD_PARTY_EXT)\

$(PJLIB_LDLIB) \

从中咱们能够看到,几乎全部编出来的静态库,都被它打包到一块儿了。

 

到这里,整个编译流程几乎已经肯定,咱们在swig目录下直接make, so文件出来了,咱们能够将android工程copy出来到eclipse或者android studio下面编译了。

 

5.android app注册

 

原始demo注册很蛋疼,选项根本不知道填什么

 

ID : 

sip:010101@58.58.32.154

Registrar: 

sip:58.58.32.154

Proxy:

sip:58.58.32.154

Username

010101

Password: 

****