语音通话模块介绍(三) CSipSimple介绍

 

CSipSimple简介

      CSipSimple是基于PJSIP开源协议库实现的Android程序,这里主要围绕CSipSimple的功能实现讲解。凡是在CSipSimple中涉及到的Android知识点以PJSIP相关内都会进一步的分析。

项目中主要有几个包:

api 包下主要是一些静态的常量,关于 sip 的管理。
db 包当然是数据库了,它也使用了标准的 ContentProvider ,其中一些建表的语句还是用 api 包中的类。
pjsip 就是这个库相关的类了,具体没有研究。在编译 jni 前,这部分是有问题的,因为它需要 jni 的调用,工程也会报错。编译后生成一些 jni 对应的调用文件就正常了,生成的文件在 org.pjsip 下。
utils 包就是一些帮助类,比如配置管理,音频自动聚焦。联系人,剪切版。
widgets 包是一些自定义的控件。
wizards 包是辅助用户的引导用的。
plugins 包是插件,没看出有什么用处。
service 包也是这里的重点:
MediaManager 音频管理的,控制不同的音频流,来电时的音频,蓝牙,静音等。
OutgoingCall 是呼出接收器,先通过这个拦截,可以拦截到系统电话的呼叫,与程序内的呼叫。然后自定义了选择器。
Downloader 处理下载的,更新的时候就是用这个下载的。默认使用的是 cacheDir 目录。
SipNotifications 是一个通知类,主要管理了通知。
SipService 这里的主要服务。
  
ui 包下就是关于界面的一些类了, account 是添加帐户的。 filters 是关于帐户的过滤的,还使用了拖动排序的 ListView
calllog 就是通话日志了。日志有选择保存在系统的通话中还是软件中。
incall 就是来电的,与通话界面了。
dialpad 是拨号面板
还有一个包是 org.webrtc.videoengine ,这里是视频通话时用到的,一看名字就知道了 camera
暂时没有找到视频的插件的源码在哪里下载。但有编译好的 apk 。使用 x264 编码。

CSipSimple框架介绍

      CSipSimple由应用层,JNI层,驱动层等组成。其中应用层和JNI层是该程序的核心,而驱动层根据设备提供。在应用层中,主要围绕了Android四大组件进行。其中:

     Activity:完成界面UI显示;

     Intent:主要是实现在ActivityActivity之间的切换

     Service:完成activity和后台之间的联系以及进程间的通信

     ContentProvider:完成数据保存及共享,主要保存一些设置,用户状态,好友等信息

     Broadcast:主要完成在系统内信息的广播,一般会和ContentProvider结合,如当数据改变了,就携带信息发送广播,当所有已注册的广播接收器接收到内容之后进行解析之后进行相应的操作。

     在JNI层,因为PJSIP核是基于C语言的,如果要用java调用,就必须封装本地的JNI库,从而实现从上到下的调用。

1 主界面

    主界面是SipHome这个Activity在该Activity中,引入了Andriod版本才有的actionBarActionBar的作用可以统一页面导航和切换方式,可以突出显示一些重要的操作,而把一些不那么重要的或者使用频率低的放在overflow中。所以这里引入了4Tab分别对应DialerFragment ,CallLogListFragmentFavListFragListFragmentConversationFragment后通过使用ViewPager实现多页面切换就可以实现这几个activity的呈现。如图1.1

 

2一些基本参数设置

  在进行相关操作,如添加用户,打电话,发送信息之前。一些必要的设置如,只使用WIFI,开启ICE功能,开启STUN功能等参数设置必不可少。所以在刚开始使用时,一般我们会打开上面介绍的设置菜单项,其路径为:com.csipsimple.ui.prefs.hc.MainPrefs这个MainPrefs。 这里讲解MainPrefs这个Acitivty是如何实现的。首先该activity使用“headers”来进行屏幕显示。其界面如图2所示,共有6header。而通过xml文件下进行相关的xml编写然后在MainPrefs中的onBuilder方法进行加载即可。而各个header都有相应的class。如图1.2Andriod使用ContentProvider来保存数据。这里参数保存,文件配置在DBProvider.classPreference中,其中DBProvider中主要和添加用户注册,信息,filter等关联。

3 添加用户(注册用户)
1 AccountsEditListFragment 中设置完相关参数信息后,跳转到 BasePrefsWizard Intent 携带 wizardId ,我们这里使用的是 Basic 类型),可根据 wizardId 进行相应 wizard 的实例显示
 
2 当设置好注册用户的相关数据之后,点击保存按钮之后进入 BasePrefsWizard 下的 saveAccount 函数,在该函数中进行了 getContentResolver ().insert 语句,即关于操作 ContentProvider 的语句。这里根据 Uri 查询后进入 DBProvider insert 方法,进而执行广播命令 getContext (). sendBroadcast ( publishIntent ).
 
3 Csipsimple 在这里注册了两个广播,一个 AccountWidgetProvider DynamicReceiver4 ,我们这里只用到 DynamicReceiver4 ,其注册方式为动态注册(在 SipService 注册了 DynamicReceiver4 广播接收器  )
 
4 当上面第二点分析的发出广播信息后,主要有两个 reciever 会做出相应的操作,分别 DynamicReceiver4 AccountWidgetProvider
 
5 DynamicReceiver4 中重写了 onReceive 即也是接收信息的函数。然后进入判断语句,上面发送的广播所携带的信息为 ACTION_SIP_ACCOUNT_CHANGED 这样的 action 根据这个 action 执行了 SipService.setAccountRegistration () 这个函数,从而跳转到 service 中执行。这里也就是用户开始注册的位置。
 
6 PJSUA 操作 : 在上面的添加用户操作中,其实已经和底层的 JNI 打交道了,如执行 SipService.setAccountRegistration () 这个函数之后就会调用底层的 JNI 库。而在执行这些 JNI 库之前。又关于 PJSUA 的一些初始化设置。这一节主要说明这个。在说明进行初始化之前,先说明下 PJSIP 库框架 ( 语音通话模块介绍())
 
7 通过 SipService onStart () 函数,加载 JNI ( 会跳到 PjSipService tryToLoadStack 方法执行 ) , 而何时进行 PJSUA 初始化, CSipSimple 中,在 SipService 开始,当注册完广播接收器之后还进行了这一步: deviceStateReceiver.startMonitoring () ,程序进入 DynamicReciever4 startMonitoring () 函数,进而在 onConnectivityChanged () 函数中调用了 SipService restartSipStack 函数,从而进入 startSipStack () 函数并调用了 pjService.sipStart () 方法。而这个 sipStart () 函数就是 PJSUA 初始化的所在处。
 
8 在 sipStart 函数中,结合 PJSIP 开发文档。从开发文档中我们知道,基础的 PJSUA-API 控制 PJSUA 的创建,初始化,启动,同时还提供各种辅助功能。在 sipStart 函数中,通过 status = pjsua.create (); 完成 pjsua 的创建,除其他事项外,还初始化 PJLIB PJLIB-UTIL ,并创建了一个 SIP endpoint 。在调用任何 PJLIB 功能之前这是至关重要的一步。
 
9  进行了上面的初始化之后,并进行一些 General Configure 。一般情况下,应用程序都将通常需要执行一些任务,使用 pjsua_transport_create () 方法(该方法是 C 语言)来创建 SIP 传输。故在 CSipSimple 中有 createTransport 这样的方法来创建 SIP 传输。完成这些初始化之后,应用程序必须调用 status = pjsua.start () 开始 PJSUA ,此函数将检查所有的配置是否正确,如果没有则采用默认配置
 
10 在前面步骤中,用户添加是从接收器 DynamicReceiver4 执行了 SipService.setAccountRegistration 这个函数开始的,确切的讲,连接底层 JNI 库的都在 PjSipService 中进行,此处也是这样。进入到 PjSipService 中的 setAccountRegistration 方法。然后根据 account 的不同情况进行不同的操作,首次添加用户将会进行这一步 status = pjsua.acc_add ( account.cfg , pjsuaConstants.PJ_FALSE , accId ) 这里 acc_add 即调用了底层的 JNI 库的 pjsuaJNI.acc_add 从而返回添加成功与否的状态。根据该状态进行相应状态的改变,从而改变显示界面,这个是内容观察者 ContentObserver 的作用,下面这个步骤分析下这个内容观察器。
 
11 在 CSipSimple 中很多地方使用了 ContentObserver 进行更新。 ContentObserver 是个内容观察者。看过 HeadFirst 模式的话就知道,其实 ContentObserver 正是基于观察者模式实现的。所谓观察者,目的就是观察(捕捉)特定的 Uri 引起的数据库变化,当其所观察的 Uri 发生改变了,便进行触发。正是因为 ContentObserver 的实现是基于观察者模式的,所以其使用显得尤其简单,我们只需创建一个特定的 ContentObserver 派生类(如图),重载父类构造函数以及 onChang () 方法处理回调后的功能实现(即观察者模式中某一事件发生变化之后进行 notify ),然后要进行相应的注册,即注册内容观察者和取消注册的步骤即基本完成操作
4 拨打电话
Java 层接口调用的是 placeCall () 函数,进入 placeCall 函数之后,如判断为 SIP 用户,则进行 SipService 方法调用,否则直接进行基本用户拨打,如图程序 :

这里只说明使用 SIP 电话拨打情况。程序调用了 SipService makeCallWithOptions 方法。进而进入 SipService makeCallWithOptions 方法。如图所示:       

这样,最终调用 PJsipService makeCall 。如图所示:       

 

 

米糊软件开发室:http://shop62437931.taobao.com/?spm=0.0.0.0

 

 

 

 


Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐