PjSIP作为SIP信令和WebRTC整合使用的方案

原创
2017/06/05 15:41
阅读数 2.3K

    PjSIP和WebRTC整合的方案Android端实现,可以正常的和其他SIP终端,如Linphone,进行音视频通话。把开发的思路和开发遇到的问题整理出来,希望能帮到大家。

 

一、编译安卓版本的PJSIP库文件

按照PjSIP的官方编译方式:

https://trac.pjsip.org/repos/wiki/Getting-Started/Android

编译命令:

TARGET_ABI=armeabi-v7a ./configure-android --use-ndk-cflags

我的Ubuntu机器会报下面的错误:

TARGET_ABI=armeabi-v7a ./configure-android --use-ndk-cflags
configure-android: APP_PLATFORM not specified, using android-24
configure-android error: compiler not found, please check environment settings (TARGET_ABI, etc)

搜索下解决方案,正确的命令如下:

NDK_TOOLCHAIN_VERSION=4.9 TARGET_ABI=armeabi-v7a APP_PLATFORM=android-19 ./configure-android --use-ndk-cflags

更新上面的错误:找到官方解答

Release notes to r13 stated that NDK_TOOLCHAIN_VERSION now defaults to Clang, resulting error on configure-android which expects gcc:

configure-android error: compiler not found, please check environment settings (TARGET_ABI, etc)
As a workaround, you can specify NDK_TOOLCHAIN_VERSION (to 4.9) to use gcc.

NDK_TOOLCHAIN_VERSION=4.9 TARGET_ABI=armeabi-v7a ./configure-android --use-ndk-cflags

 

编译完成之后,会在每个子目录下的lib下生成对应的.a文件,如pjsip:

pjsip/lib/
├── libpjsip-arm-unknown-linux-androideabi.a
├── libpjsip-simple-arm-unknown-linux-androideabi.a
├── libpjsip-ua-arm-unknown-linux-androideabi.a
├── libpjsua2-arm-unknown-linux-androideabi.a
└── libpjsua-arm-unknown-linux-androideabi.a

0 directories, 5 files

 

二、编译自己的动态库

    自己的动态库是基于PjSIP,然后进行的分装,简化了SIP注册,呼叫和接听功能,增加了额外一些功能。这个动态库最终会放在Android Studio下面,通过JNI分装成Java类给上层调用。

    我的头文件部分结接口:

int rtc_engine_init(const rtc_cb *cb); 
int rtc_engine_start(); 
int rtc_engine_stop(); 
int rtc_engine_destroy(); 
 
int set_reg_cfg(const char* username, const char *psw, const char *proxy); 
 
int start_register(); 
int destroy_register(); 
int unregister(); 
int reflesh_register(); 
 
int make_call(const char *dst_num, char *sdp_str); 
int cancel_call(); 

  

    构建动态库是通过Cmake实现的,CMakeLists.txt如下:

cmake_minimum_required (VERSION 3.5)
project (SIPClient)                                                                                                                                                                                       
 
set(TARGET_NAME arm-unknown-linux-androideabi)
set(ZLSIP_INC ${CMAKE_CURRENT_LIST_DIR}/../include)
 
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu99 ")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu99") 
add_definitions(-DPJ_AUTOCONF)
 
include_directories(${ZLSIP_INC}
    ${ZLSIP_INC}/pjlib
    ${ZLSIP_INC}/pjlib-util
    ${ZLSIP_INC}/pjsip
    ${ZLSIP_INC}/pjsip-ua
    ${ZLSIP_INC}/pjsip-simple
    ${ZLSIP_INC}/pjmedia
    )
 
link_directories(${CMAKE_CURRENT_LIST_DIR}/../libs)
 
add_library(sip_client SHARED sip_client.c)
 
target_link_libraries(sip_client
                        pjsip-ua-${TARGET_NAME}
                        pjsip-simple-${TARGET_NAME}
                        pjsip-${TARGET_NAME}
                        pjsdp-${TARGET_NAME} 
                        pjlib-util-${TARGET_NAME}
                        pj-${TARGET_NAME}
                        )                         

 

遇到的一个问题:

编译动态库时,使用的时cmake,默认情况下会出现:

/usr/bin/ld: /home/wangweichao/Documents/PjSip/trunk-new/wang_pjsip/src/../libs/libpj-x86_64-unknown-linux-gnu.a(ioqueue_select.o): relocation R_X86_64_32 against `.rodata' can not be used when making a shared object; recompile with -fPIC
/home/wangweichao/Documents/PjSip/trunk-new/wang_pjsip/src/../libs/libpj-x86_64-unknown-linux-gnu.a: error adding symbols: Bad value
collect2: error: ld returned 1 exit status

解决方案: 需要重新PJSIP的动态库加入 -fPIC编译选项

 

三、动态库导入到AppRTCDemo的安卓工程中

    把编译出来的动态库SO文件,导入到AppRTCDemo工程中,放在JNI文件下,实现自己的Android.mk和Java的含有的Native方法的类。具体如何通过JNI调用C动态库和头文件,可以查看其他博客。

    例如我的JAVA类对应的Native的方法片段:

    public  native boolean rtcEngineInit(SipChannelObserver var);
    public  native boolean rtcEngineStart();
    public  native boolean rtcEngineStop();
    public  native boolean rtcEngineDestroy();
    public  native boolean setRegConfig(String userName, String password, String proxy);

    public  native boolean startRegister();
    public  native boolean destroyRegister();
    public  native boolean unRegister();
    public  native boolean refleshRegister();

    public  native boolean makeCall(String dstNumber, String sdpStr);
    public  native boolean cancelCall();

    public  native boolean acceptCall(String sdpStr);
    public  native boolean denyCall();

 

 我的工程对应的Android.mk,重新生成一个libsip_channel.so的动态库,并使用了我们自己动态库libsip_client.so和webrtc的动态库libjingle_peerconnection_so.so动态库。

LOCAL_PATH := $(call my-dir)  

include $(CLEAR_VARS)
LOCAL_MODULE    := sip_channel
LOCAL_CFLAGS :=
LOCAL_C_INCLUDES := $(LOCAL_PATH)
LOCAL_SHARED_LIBRARIES := sip_client
LOCAL_SRC_FILES := org_appspot_apprtc_SIPChannelClient.c
LOCAL_LDLIBS:=-L$(SYSROOT)/usr/lib -llog
include $(BUILD_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := sip_client
LOCAL_SRC_FILES := libsip_client.so
include $(PREBUILT_SHARED_LIBRARY)

include $(CLEAR_VARS)
LOCAL_MODULE := jingle_peerconnection_so
LOCAL_SRC_FILES := libjingle_peerconnection_so.so
include $(PREBUILT_SHARED_LIBRARY)

 

遇到的一个架构不支持的问题

由于我当前编译出来只是armeabi-v7a的库,最开始时,会有

error: linker command failed with exit code 1 (use -v to see invocation) 

这个错误提示,打开AS右下角的Gradle Console看到:

* What went wrong:
Execution failed for task ':app:externalNativeBuildDebug'.
> Build command failed.
Error while executing process C:\Users\Administrator\AppData\Local\Android\Sdk\ndk-bundle\ndk-build.cmd with arguments {NDK_PROJECT_PATH=null APP_BUILD_SCRIPT=F:\RtcAndroid\AppRTCDemo-master\app\jni\Android.mk NDK_APPLICATION_MK=F:\RtcAndroid\AppRTCDemo-master\app\jni\Application.mk APP_ABI=mips64 NDK_ALL_ABIS=mips64 NDK_DEBUG=1 APP_PLATFORM=android-21 NDK_OUT=F:/RtcAndroid/AppRTCDemo-master/app/build/intermediates/ndkBuild/debug/obj NDK_LIBS_OUT=F:\RtcAndroid\AppRTCDemo-master\app\build\intermediates\ndkBuild\debug\lib F:/RtcAndroid/AppRTCDemo-master/app/build/intermediates/ndkBuild/debug/obj/local/mips64/libsip_channel.so}
[mips64] SharedLibrary  : libsip_channel.so
F:/RtcAndroid/AppRTCDemo-master/app/build/intermediates/ndkBuild/debug/obj/local/mips64/libzl_sip_client.so: error adding symbols: File in wrong format
clang++.exe: error: linker command failed with exit code 1 (use -v to see invocation)
make: *** [F:/RtcAndroid/AppRTCDemo-master/app/build/intermediates/ndkBuild/debug/obj/local/mips64/libsip_channel.so] Error 1

 

意思时缺少MIPS的动态库,因为我不编译MIPS的动态库,我需要在build.gradle中设置 ndk的abiFilters来告诉程序只编译armeabi-v7a的库:

defaultConfig {
    applicationId "org.appspot.apprtc"
    minSdkVersion 16
    targetSdkVersion 25

    ndk{
      abiFilters  "armeabi-v7a" //"armeabi", "armeabi-v7a", "x86" //输出指定三种平台下的so库
    }
}

 

 

    这篇文章着重在于使用PjSIP编译成安卓使用动态库,并通过JNI调用,在安卓层实现SIP信令。SIP信令和WebRTC结合,还包括JAVA层WebRTC的SDP和ICE的搜集组合成供sip信令使用的SDP,还有反过来的解析。后面有时间再写另外一篇文章讲讲。

   

 

展开阅读全文
打赏
0
0 收藏
分享
加载中

引用来自“shing1”的评论

你好,想问下您关于pjsip和webrtc的安卓客户端实现还有后续文章吗?关于SIP信令是怎么实现我还是没太懂

引用来自“行者无疆在杭州”的评论

pjsip这个开源库里面有sip协议栈,可以直接使用
主要是SIP信令和webrtc结合是怎么结合没太懂。把信令层换成sip协议栈,然后设定好用户名密码和domain就能和linphone客户端互联了吗?
2018/10/30 19:13
回复
举报

引用来自“shing1”的评论

你好,想问下您关于pjsip和webrtc的安卓客户端实现还有后续文章吗?关于SIP信令是怎么实现我还是没太懂
pjsip这个开源库里面有sip协议栈,可以直接使用
2018/10/30 09:07
回复
举报
你好,想问下您关于pjsip和webrtc的安卓客户端实现还有后续文章吗?关于SIP信令是怎么实现我还是没太懂
2018/10/29 21:40
回复
举报
更多评论
打赏
3 评论
0 收藏
0
分享
返回顶部
顶部