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

来源:互联网 发布:图像经典算法 编辑:程序博客网 时间:2024/05/04 11:32

语音通话模块介绍(三) 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中设置完相关参数信息后,跳转到BasePrefsWizardIntent携带wizardId,我们这里使用的是Basic类型),可根据wizardId进行相应wizard的实例显示
 
2 当设置好注册用户的相关数据之后,点击保存按钮之后进入BasePrefsWizard下的saveAccount函数,在该函数中进行了getContentResolver().insert语句,即关于操作ContentProvider的语句。这里根据Uri查询后进入DBProviderinsert方法,进而执行广播命令getContext().sendBroadcast(publishIntent).
 
3 Csipsimple在这里注册了两个广播,一个AccountWidgetProviderDynamicReceiver4,我们这里只用到DynamicReceiver4,其注册方式为动态注册(在SipService注册了DynamicReceiver4广播接收器  )
 
4 当上面第二点分析的发出广播信息后,主要有两个reciever会做出相应的操作,分别DynamicReceiver4AccountWidgetProvider
 
5 DynamicReceiver4中重写了onReceive即也是接收信息的函数。然后进入判断语句,上面发送的广播所携带的信息为ACTION_SIP_ACCOUNT_CHANGED这样的action根据这个action执行了SipService.setAccountRegistration()这个函数,从而跳转到service中执行。这里也就是用户开始注册的位置。
 
6 PJSUA操作:在上面的添加用户操作中,其实已经和底层的JNI打交道了,如执行SipService.setAccountRegistration()这个函数之后就会调用底层的JNI库。而在执行这些JNI库之前。又关于PJSUA的一些初始化设置。这一节主要说明这个。在说明进行初始化之前,先说明下PJSIP库框架(语音通话模块介绍())
 
7 通过SipServiceonStart()函数,加载JNI(会跳到PjSipServicetryToLoadStack方法执行) ,而何时进行PJSUA初始化,CSipSimple中,在SipService开始,当注册完广播接收器之后还进行了这一步:deviceStateReceiver.startMonitoring(),程序进入DynamicReciever4startMonitoring()函数,进而在onConnectivityChanged()函数中调用了SipServicerestartSipStack函数,从而进入startSipStack()函数并调用了pjService.sipStart()方法。而这个sipStart()函数就是PJSUA初始化的所在处。
 
8 在sipStart函数中,结合PJSIP开发文档。从开发文档中我们知道,基础的PJSUA-API控制PJSUA的创建,初始化,启动,同时还提供各种辅助功能。在sipStart函数中,通过status = pjsua.create();完成pjsua的创建,除其他事项外,还初始化PJLIBPJLIB-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电话拨打情况。程序调用了SipServicemakeCallWithOptions方法。进而进入SipServicemakeCallWithOptions方法。如图所示:      

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

 

 

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