sip在sdk中有三个目录:server、net、telephony;
以下是针对net目录下Sip的分析:
net目录包含九个目标文件(SimpleSessionDescription、SipAudioCall、SipErrorCode、SipException、SipManager、SipProfile、SipRegistrationListener、SipSession、SipSessionAdapter)。
- public class SipErrorCode 该类定义了Sip错误代码,定义如下:
- /** Not an error. 未定义错误 */
- public static final int NO_ERROR = 0;
- /** When some socket error occurs. 当一些发生套接字错误。 */
- public static final int SOCKET_ERROR = -1;
- /** When server responds with an error. 当服务器响应一个错误。*/
- public static final int SERVER_ERROR = -2;
- /** When transaction is terminated unexpectedly. 当交易被意外终止。*/
- public static final int TRANSACTION_TERMINTED = -3;
- /** When some error occurs on the device, possibly due to a bug. 当一些错误发生在设备上,这可能是由于一个错误。*/
- public static final int CLIENT_ERROR = -4;
- /** When the transaction gets timed out. 当事务被超时。*/
- public static final int TIME_OUT = -5;
- /** When the remote URI is not valid. 当远程URI是无效的。*/
- public static final int INVALID_REMOTE_URI = -6;
- /** When the peer is not reachable. 当对端不可达。*/
- public static final int PEER_NOT_REACHABLE = -7;
- /** When invalid credentials are provided. 当无效的凭证。*/
- public static final int INVALID_CREDENTIALS = -8;
- /** The client is in a transaction and cannot initiate a new one. 客户在交易中不能启动一个新的。*/
- public static final int IN_PROGRESS = -9;
- /** When data connection is lost. 当数据连接丢失。*/
- public static final int DATA_CONNECTION_LOST = -10;
- /** Cross-domain authentication required. 跨域认证。*/
- public static final int CROSS_DOMAIN_AUTHENTICATION = -11;
- /** When the server is not reachable. 当服务器不可达。*/
- public static final int SERVER_UNREACHABLE = -12;
- public interface SipRegistrationListener SIP注册事件监听器
- 该类包含了三个回调函数:
- void onRegistering(String localProfileUri) 发送的注册请求时调用
- void onRegistrationDone(String localProfileUri, long expiryTime) 注册成功时调用
- onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) 注册失败时调用
- public class SipException extends Exception 表示一般的SIP相关的异常。
- public class SipSessionAdapter extends ISipSessionListener.Stub 会话适配器类 会话监听
- 该类定义了一些通话事件,如下:
- public void onCalling(ISipSession session) { // 正通话中
- }
- public void onRinging(ISipSession session, SipProfile caller, String sessionDescription) { // 响铃
- }
- public void onRingingBack(ISipSession session) {
- }
- public void onCallEstablished(ISipSession session, String sessionDescription) { //建立通话
- }
- public void onCallEnded(ISipSession session) { //通话结束
- }
- public void onCallBusy(ISipSession session) { //通话忙
- }
- public void onCallTransferring(ISipSession session, String sessionDescription) { //呼叫转移
- }
- public void onCallChangeFailed(ISipSession session, int errorCode, String message) { //打电话失败
- }
- public void onError(ISipSession session, int errorCode, String message) { //错误
- }
- public void onRegistering(ISipSession session) { //正在注册
- }
- public void onRegistrationDone(ISipSession session, int duration) { //注册完成
- }
- public void onRegistrationFailed(ISipSession session, int errorCode, String message) { //注册失败
- }
- public void onRegistrationTimeout(ISipSession session) { //注册超时
- }
- public class SipProfile implements Parcelable, Serializable, Cloneable 定义一个SIP配置文件
- 包括一个SIP帐户、传输协议、端口、密码、文件、id、域和服务器等的信息!
- public static class Builder 辅助类,辅助构造一个SIP配置文件
- public final class SipSession Sip会话信息
- 该类中定义了一个状态类State(,如“注册”,“呼出”,和“呼叫) 定义如下:
- /** When session is ready to initiate a call or transaction. 当会话已准备好发起呼叫或交易。*/
- public static final int READY_TO_CALL = 0;
- /** When the registration request is sent out. 当注册请求被发送出去。*/
- public static final int REGISTERING = 1;
- /** When the unregistration request is sent out. 当注销请求发送出去。*/
- public static final int DEREGISTERING = 2;
- /** When an INVITE request is received. 当INVITE请求被接受。*/
- public static final int INCOMING_CALL = 3;
- /** When an OK response is sent for the INVITE request received.
- * 当一个OK响应发送的INVITE请求。*/
- public static final int INCOMING_CALL_ANSWERING = 4;
- /** When an INVITE request is sent.
- * 当INVITE请求被发送。 */
- public static final int OUTGOING_CALL = 5;
- /** When a RINGING response is received for the INVITE request sent.
- * RINGING响应当接收到发送的INVITE请求。 */
- public static final int OUTGOING_CALL_RING_BACK = 6;
- /** When a CANCEL request is sent for the INVITE request sent.
- * 当一个CANCEL请求被发送的INVITE请求发送。 */
- public static final int OUTGOING_CALL_CANCELING = 7;
- /** When a call is established. 当一个呼叫建立。*/
- public static final int IN_CALL = 8;
- /** When an OPTIONS request is sent. 当一个OPTIONS请求被发送。*/
- public static final int PINGING = 9;
- /** When ending a call. @hide 结束一个呼叫时*/
- public static final int ENDING_CALL = 10;
- /** Not defined. 没有定义*/
- public static final int NOT_DEFINED = 101;
- 还定义了一个监听类Listener 一个SIP会话有关的事件 如下:
- public void onCalling(SipSession session) 当INVITE请求被发送到发起新的呼叫调用
- public void onRinging(SipSession session, SipProfile caller,String sessionDescription) 收到INVITE请求时调用
- public void onRingingBack(SipSession session) RINGING收到响应发送的INVITE请求时,调用
- public void onCallEstablished(SipSession session,String sessionDescription) 在会话建立时调用
- public void onCallEnded(SipSession session) 在会话终止时调用
- public void onCallBusy(SipSession session) 所谓同行是忙时会话初始化过程中
- public void onCallTransferring(SipSession newSession,String sessionDescription) 呼叫时,呼叫被转移到一个新的
- public void onError(SipSession session, int errorCode,String errorMessage) 会话初始化和终止过程中发生错误时调用
- public void onCallChangeFailed(SipSession session, int errorCode,String errorMessage) 更改会话协商过程中发生错误时调用
- public void onRegistering(SipSession session) 发送的注册请求时调用
- public void onRegistrationDone(SipSession session, int duration) 注册成功完成时调用
- public void onRegistrationFailed(SipSession session, int errorCode,String errorMessage) 注册失败时调用
- public void onRegistrationTimeout(SipSession session) 登记被超时时调用
- 会话过程中,定义了一些回调如:
- private ISipSessionListener createListener()
- public class SimpleSessionDescription 使用的对象来处理消息的会话描述协议(SDP)。它主要是设计用于的会话发起协议(SIP)的用途。
- 该类中还定义了Media 表示一个媒体描述,会话描述(类型、端口、协议、格式、解码/编码)!
- public class SipAudioCall 处理SIP的互联网音频呼叫
- public class SipManager 提供了API,SIP的任务,如启动SIP连接,并提供相关的SIP服务的访问。 如下方法:
- public static boolean isApiSupported(Context context) 系统是否支持SIP API
- public static boolean isVoipSupported(Context context) 系统是否支持基于SIP协议的VOIP API
- public static boolean isSipWifiOnly(Context context) SIP是否仅适用于WIFI
- public SipAudioCall makeAudioCall(SipProfile localProfile, SipProfile peerProfile, SipAudioCall.Listener listener, int timeout) 创建一个拨打
- 电话
- public SipAudioCall takeAudioCall(Intent incomingCallIntent,SipAudioCall.Listener listener) 创建一个接听来电
- public static boolean isIncomingCallIntent(Intent intent) 如果目的是检查呼入广播意图
- public static String getOfferSessionDescription(Intent incomingCallIntent) 从指定的来电广播意图获取提供会话描述
- public void register(SipProfile localProfile, int expiryTime,SipRegistrationListener listener) 手动注册的配置文件,相应的SIP提供商接听电话。
- public void unregister(SipProfile localProfile,SipRegistrationListener listener) 手动注销相应的SIP为进一步呼吁停止接收供应商的档案,这可能会
- 干扰自动注册的SIP服务的过程中,如果在配置文件中启用了自动注册选项。
- 内部含有:private static class ListenerRelay extends SipSessionAdapter 类负责监听注册过程的回调!
以上是针对net目录下Sip的分析,好了我们转到server目录下Sip的分析。server目录下有六个目标文件(SipHelper、SipService、SipSessionGroup、SipSessionListenerProxy、SipWakeLock、SipWakeupTimer)。
- class SipHelper SIP协议栈相关的类和各种低级别的SIP任务,如发送消息的Helper类,产生会话需要的消息头/体的各种信息,定义如下:
- private FromHeader createFromHeader(SipProfile profile, String tag) //构造来自源头信息
- private ToHeader createToHeader(SipProfile profile) throws ParseException { //构造去向源信息
- private ToHeader createToHeader(SipProfile profile, String tag) //构造去向源信息
- private CallIdHeader createCallIdHeader() {//构造会话id信息
- private CSeqHeader createCSeqHeader(String method) //构造会话CSeq信息
- private MaxForwardsHeader createMaxForwardsHeader() //构造会话MaxForwards信息
- private List<ViaHeader> createViaHeaders() //构造通道信息
- private ContactHeader createContactHeader(SipProfile profile) //构造联系头
- private ContactHeader createWildcardContactHeader() { //创建通配符
- private SipURI createSipUri(String username, String transport,
- ListeningPoint lp) throws ParseException { //构造sip地址
- public ClientTransaction sendOptions(SipProfile caller, SipProfile callee,
- String tag) throws SipException { //发送选择
- public ClientTransaction sendRegister(SipProfile userProfile, String tag,
- int expiry) throws SipException { //发送注册
- private Request createRequest(String requestType, SipProfile userProfile,
- String tag) throws ParseException, SipException { //创建请求
- public ClientTransaction handleChallenge(ResponseEvent responseEvent,
- AccountManager accountManager) throws SipException { //处理请求
- private Request createRequest(String requestType, SipProfile caller,
- SipProfile callee, String tag) throws ParseException, SipException { //创建请求
- public ClientTransaction sendInvite(SipProfile caller, SipProfile callee,
- String sessionDescription, String tag, ReferredByHeader referredBy,
- String replaces) throws SipException { //发送邀请
- public ClientTransaction sendReinvite(Dialog dialog,
- String sessionDescription) throws SipException { //发送再次邀请
- public ServerTransaction getServerTransaction(RequestEvent event)
- throws SipException { //得到服务器中交易信息
- public ServerTransaction sendRinging(RequestEvent event, String tag)
- throws SipException { //发送响铃
- public ServerTransaction sendInviteOk(RequestEvent event,
- SipProfile localProfile, String sessionDescription,
- ServerTransaction inviteTransaction, String externalIp,
- int externalPort) throws SipException { //邀请OK
- public void sendInviteBusyHere(RequestEvent event,
- ServerTransaction inviteTransaction) throws SipException { //邀请忙
- public void sendInviteAck(ResponseEvent event, Dialog dialog)
- throws SipException { //发送邀请ack
- public void sendReferNotify(Dialog dialog, String content)
- throws SipException { //发送参阅通知
- public void sendInviteRequestTerminated(Request inviteRequest,
- ServerTransaction inviteTransaction) throws SipException { //发送邀请终止
- public final class SipService extends ISipService.Stub 管理Sip的服务
- class SipSessionGroup implements SipListener 管理的一个SIP帐户
- class SipSessionListenerProxy extends ISipSessionListener.Stub 以帮助安全地运行在不同的线程中的回调,实现会话过程中事件
- class SipWakeLock 定义了sip同步锁
- class SipWakeupTimer extends BroadcastReceiver 定时器,它可安排事件的发生,甚至当设备处于睡眠。
- 该类是继承了广播,类中还定义了
- private static class MyEvent 事件以及回调
- private static class MyEventComparator implements Comparator<MyEvent> 用于对准的事件与较大的期间,对事件排序
以上是针对server目录下Sip的分析,好了我们转到telephony目录下Sip的分析。telephony目录下有六个目标文件(SipCallBase、SipCommandInterface、SipConnectionBase、SipPhone、SipPhoneBase、SipPhoneFactory)。
- public class SipPhoneFactory sip电话生成厂
- abstract class SipPhoneBase extends PhoneBase 记录/管理Sip电话状态类
- public class SipPhone extends SipPhoneBase 同上
- abstract class SipConnectionBase extends Connection 记录Sip电话时间等信息
- class SipCommandInterface extends BaseCommands implements CommandsInterface SIP不需要CommandsInterface的。类什么也不做,但PhoneBase的构造函数
- 所做的工作。
- abstract class SipCallBase extends Call 抽象类,记录连接信息。
以上是针对telephony目录下Sip的分析。其它引用分析如下:
如下是SipPhone实现相关类图。
SipPhone对象虽然也派生自PhoneBase,但实现机制及实例化过程与其它Phone对象大大不同。
SipPhone对象的实例化通过PhoneFactory的makeSipPhone的接口调用SipPhoneFactory的makePhone进行实例化。
SipPhone对象的实例化调用也不是在PhoneApp对象中进行,而是在默认电话应用的SipBroadcastReceiver对象的onReceive回调函数或者SipCallOptionHandler对象的createSipPhoneIfNeeded函数中被调用,另外不同的是对SipPhone对象的创建个数也没有限制。
虽然实例化过程和CDMAPhone、GSMPhone对象不同,但实例化的SipPhone对象和CDMAPhone、GSMPhone对象一样也被添加到CallManager对象中进行统一管理。
SipPhone实现机制是通过IP通道实现电话功能,而不是通过无线通讯模块,因此没有采用RIL和RIL daemon,因此框架实现层与CDMAPhone、GSMPhone有很大不同,SipPhone框架实现主要是通过SipService系统服务及调用第三方协议栈来完成。
SipService系统服务通过JNI来调用本地nist SIP协议堆栈。
SipPhone对象属于SipService服务的客户端对象,其通过SipManager对象的ISipService接口调用SipService。
每个SipPhone对象都对应一个SipProfile对象(包括SIP帐户,地址连接信息以及服务信息等信息)用来标识通话一方。
SipProfile对象在SipPhoneFactory调用makePhone实例化SipPhone对象前根据网络通话的sipUri构建,并作为makePhone的参数传给SipPhone对象。
每个SipPhone对象和其它具体Phone对象相同也包括三个Call对象(SipCall):ringingCall、foregroundCall、backgroundCall,每个SipCall对象也包含一个Connection类型的ArrayList对象,用来维护每个CALL拥有的通话连接。
不过和其它Phone对象不同SipPhone对象对每个Call对象拥有的connection个数没有限制,SipCall拥有的connection对象对应具体的SipConnection对象。
SipConnection对象包括主动和被动两种类型,主动类型的SipConnection对象在SipCall对象的dial函数调用时创建,被动类型的SipConnection对象在SipCall对象接收到输入CALL时,其initIncomingCall函数调用时创建。
创建的SipConnection对象添加到SipCall对象的Connection类型的ArrayList数组列表中进行管理。
每个SipConnection对象也包括一个SipProfile对象和一个SipAudioCall对象。
被动SipConnection类型的SipProfile对象和SipAudioCall对象从对方获得。
被动类型的SipAudioCall对象和initIncomingCall函数传进来的SipAudioCall对象相同,SipProfile对象通过调用SipAudioCall的getPeerProfile函数获得发起通话的对方的SipProfile。
主动SipConnection类型的SipProfile对象在dial函数中调用SipProfile.Builder对象的build函数根据发起的通话URL构建,用来标识本地通话方,SipAudioCall对象在调用dial函数时通过调用SipManager对象的makeAudioCall函数创建。
SipAudioCall对象中包括一个客户端SipSession对象,管理客户端的每一个会话过程,SipSession对象中有一个ISipSession接口成员,通过该接口调用服务端对应的会话对象SipSessionImpl对象(一个实现ISipSession接口的会话桩对象),共同完成通话一方的会话过程,客户端通过ISipSession接口向服务端的SipSessionImpl对象发起IPC调用。
主动类型的SipAudioCall对象对应的SipSession对象在makeAudioCall函数中调用createSipSession进行实例化,在makeAudioCall函数调用新创建SipAudioCall对象的makeCall函数时,SipSession对象作为makeCall函数的参数传给SipAudioCall对象。
主动类型的SipSession对象中的ISipSession类型的接口成员在createSipSession中通过调用SipService的createSession函数创建,返回服务端SipSessionImpl对象的远程调用对象接口。
SipService的createSession函数创建一个Sip会话对象的整个过程:
1、首先调用createGroup函数实例化一个SipSessionGroupExt对象,SipSessionGroupExt对象派生自SipSessionAdapter,而SipSessionAdapter是一个实现ISipSessionListener接口的桩类;
2、SipSessionGroupExt对象实例化时又调用createSipSessionGroup函数实例化一个SipSessionGroup对象;
3、SipSessionGroup对象实例化时由SipFactory工厂对象实例化底层协议栈类对象SipStack,并有SipStack对象创建一个SipProvider对象和一个SipHelper对象,SipSessionGroup对象本身登记为SipProvider对象的监听对象;
4、然后调用SipSessionGroupExt对象的createSession函数,内部实际调用SipSessionGroup对象的createSession函数,实例化SipSessionImpl对象,并返回实例化后的SipSessionImpl对象引用。
5、SipSessionImpl属于SipSessionGroup类的内部类,客户端发起的通话请求都通过服务端的SipSessionImpl对象封装成EventObject类型的命令发起异步处理请求(调用SipSessionImpl对象的doCommandAsync函数,doCommandAsync函数的参数是一个EventObject类型的对象),最终通过SipSessionGroup对象的SipHelper对象调用SIP协议栈的接口与通话对方交互。
6、每个SipSessionImpl会话对象被放到SipSessionGroup对象的HashMap中进行管理。每个实例化的SipSessionGroupExt对象放到SipService的HashMap中进行管理。
客户端也可以通过SipManager对象的open函数发起一个被动会话请求,过程为:
1、 SipManager对象的open函数调用SipService的open3函数,同时也实例化一个PendingIntent对象通过SipService的open3函数传给服务端的SipSessionGroupExt对象中;
2、 在open3函数中调用createGroup函数实例化SipSessionGroupExt对象,并进一步实例化SipSessionGroup对象;
3、 接着调用SipSessionGroup对象的openToReceiveCalls函数来实例化一个SipSessionCallReceiverImpl对象作为接收会话,SipSessionCallReceiverImpl派生自SipSessionImpl,SipSessionGroupExt对象作为函数参数传进openToReceiveCalls函数,并在SipSessionImpl构造函数时调用内部对象成员mProxy(SipSessionListenerProxy类,一个实现ISipSessionListener接口的桩类)的setListener函数,为内部ISipSessionListener类型的成员赋值。
4、 当接收到底层协议发来的会话请求时,监听底层事件的对象SipSessionGroup的processRequest函数被调用;
5、 接着调用接收会话对象SipSessionCallReceiverImpl的process函数,在process函数中判断接收到的事件请求是Request.INVITE时就调用processNewInviteRequest函数;
6、 在processNewInviteRequest函数中调用createNewSession实例化一个SipSessionImpl对象作为新的会话,新的会话状态为INCOMING_CALL。接着调用接收会话SipSessionCallReceiverImpl对象内部成员mProxy的onRinging函数,在onRinging函数中调用其成员mListener(ISipSessionListener类型)的onRinging函数,实际调用SipSessionGroupExt对象的onRinging函数;
7、 在SipSessionGroupExt对象的onRinging函数中通过SipSessionGroupExt对象内部客户端传进来的PendingIntent对象向客户端发送ACTION_SIP_INCOMING_CALL类型广播消息;
8、 客户端在接收到这个广播调用SipManager的takeAudioCall函数。takeAudioCall函数首先通过SipService接口getPendingSession获得一个服务端会话对象引用;接着实例化一个SipAudioCall对象(SipAudioCall对象对应的SipProfile对象调用服务端会话对象的getLocalProfile函数获得);然后根据服务端会话对象引用实例化一个客户端SipSession对象;并调用SipAudioCall对象的attachCall实现SipSession对象与SipAudioCall对象的绑定;
9、 最后调用现有的SipPhone对象的canTake函数,在SipPhone对象的canTake函数中调用SipPhone对象的ringingCall对象的initIncomingCall函数实例化一个SipConnection对象,完成通话建立过程。
Telephony框架的数据连接模块负责数据连接通道的建立,使电话能够提供数据服务,如上网等,数据连接模块的类图如下图。
DataConnectionTracker是数据连接功能的核心,GsmDataConnectionTracker、CdmaDataConnectionTracker是DataConnectionTracker的两个派生类,实现具体网络的数据连接的建立和管理。
每一个数据连接用一个DataConnection对象表示,DataConnection对应的具体网络的派生类为GsmDataConnection和CdmaDataConnection。DataConnectionTracker中用一个HashMap类型的变量mDataConnections维护每一个数据连接。CDMA同时只能建立一路数据连接,GSM网络则没有限制。
DataConnection对象是一个是一个状态机对象,维护连接的状态,并提供数据连接的LinkProperties和LinkCapabilities等属性。DataConnection对象的状态包括DcDefaultState、DcInactiveState、DcActivatingState、DcActiveState、DcDisconnectingState、DcDisconnectionErrorCreatingConnection六种状态。
对于GsmDataConnectionTracker对象,ApnContext对象提供数据连接的APN上下文,每一个APN类型都对应一个ApnContext对象,ApnContext对象维护对应的APN设置、DataConnectionTracker的状态、对应的DataConnection和DataConnectionAc等。
数据连接通道的建立过程:
1、 数据连接的建立最终都通过GsmDataConnectionTracker和CdmaDataConnectionTracker的trySetupData函数启动数据连接;
2、 trySetupData函数调用setupData函数,设置数据连接参数(如采用的Apn设置参数,连接建立成功响应消息);
3、 然后调用对应的DataConnection对象的bringUp函数发送数据连接消息(EVENT_CONNECT)。
4、 EVENT_CONNECT消息由DataConnection对象的状态机的相应状态对象接收处理,对于开始尚未建立数据连接时,DataConnection对象处于DcInactiveState状态,因此DcInactiveState状态对象接收处理EVENT_CONNECT事件,调用onConnect函数,并转变为DcActivatingState状态。
5、 在具体DataConnection对象的onConnect函数中调用RIL接口setupDataCall函数启动数据连接;
6、 连接建立后RIL层回应EVENT_SETUP_DATA_CONNECTION_DONE请求应答事件,由DataConnection对象的DcActivatingState状态对象接收处理EVENT_SETUP_DATA_CONNECTION_DONE事件,调用onSetupConnectionCompleted函数,并过渡到DcActiveState状态,连接建立成功。
DataConnectionTracker对象采用DataConnectionAc对象(派生自AsyncChannel)与DataConnection对象通讯。
smDataConnectionTracker对象在setupData函数调用createDataConnection函数创建时GsmDataConnection对象和DataConnectionAc对象,并通过DataConnectionAc对象与GsmDataConnection对象建立异步通讯连接。GsmDataConnectionTracker对象对于每类ApnContext都可以建立一个GsmDataConnection对象和一个DataConnectionAc对象。
CdmaDataConnectionTracker对象在实例化时调用createAllDataConnectionList函数创建需要的数据连接对象CdmaDataConnection和DataConnectionAc对象。CdmaDataConnectionTracker对象只支持创建一个CdmaDataConnection对象和DataConnectionAc对象。
整个Telephony事件通知框架包括三层: RIL消息层、框架事件处理层、应用层。类图如下图,主要是请求应答模式和观察者模式的采用。
整个框架层以PhoneBase为中心,向上通过PhoneNotifier接口向应用层发送框架层产生的的事件,应用层通过TelephonyRegistry接口提供对特定事件的监听,由PhoneNotifier接口的默认实现DefaultPhoneNotifier通过TelephonyRegistry对象向应用层发送事件通知。
向下框架层通过CommandsInterface接口注册Unsolicited事件(主动通知事件)及发起AT命令请求。框架层的事件处理对象包括CDMAPhone和GSMPhone两个对象本身及其包含的SMSDispatcher、IccFileHandler、DataConnectionTracker、IccRecords类型的对象以及PhoneBase中的SmsStorageMonitor对象。
这些对象都是Handler对象,都能够向RIL层注册Unsolicited事件及发起AT命令请求。也能够接收和处理RIL层产生的Unsolicited事件及AT命令的响应。
CDMAPhone和GSMPhone对象中的事件处理对象除了CallTracker及ServiceStateTracker对象外,其它都在PhoneBase中由基类实现。
向RIL层注册的Unsolicited事件都登记添加到BaseCommands类中的RegistrantList类型的对象中或者设置为BaseCommands类中的Registrant类型的对象(根据设置函数的参数实例化具体类型的Registrant类型的对象)。
RIL层产生的Unsolicited事件通过在BaseCommands类中登记的RegistrantList对象或设置的Registrant对象向框架层的事件处理对象发送Unsolicited事件。
框架层的事件处理对象向RIL层发送的命令直接发送给RIL对象的相应函数,向RIL层发送的命令中都带有一个Message类型的应答消息,RIL对象的相应函数把接收到的命令携带的参数封装进RILRequest请求中发送给RIL的RILSender对象并marshall后通过LocalSocket发送给rild进程。
RIL的RILReceiver对象通过相同LocalSocket通道收到AT命令的响应unmarshall后调用processSolicited()函数把应答结果封装进命令携带的应答消息中发送回框架层的事件处理对象。
RILSender对象和RILReceiver对象都实现了接口,在独立线程运行。
官方提供的实例中有关sip的就一个(SipDemo),下面是对它的分析:
一、基本概念
1、VOIP基于SIP协议,SDK2.3包含一个SIP协议栈和框架API
2、VOIP位于android.net.sip包中,最重要的为SipManager类,可开发基于SIP的VOIP应用。使用时要包含android.permission.INTERNET和android.permission.USE_SIP权限
3、如果在market中显示仅支持VOIP API幸好的手机的话,发布时需要在androidManifest.xml中加入<uses_feature android:name = "android.software.sip" android:required = "true">和<uses_feature android:name = "android.software.sip.voip">
4、要支持SIP API
(1)仅Android2.3或更高版本平台支持
(2)不是所有设备都提供SIP支持,确保你的APP只安装在支持SIP的装置上
5、根据GOOGLE官方DEMO项目来扩展的概念
二、类及方法描述
1、一个基本的VOIP项目至少需要三个类SIPSettings(对SIP的基本设置身份验证)、WalkieTalkieActivity(登录到SIP设备供应商,注册device去处理来电,拨打电话,在通话过程中用户界面管理)、IncomingCallReceiver(监听传入的SIP电话,然后传递这些SIP电话给WalkieTalkieActivity控制)
2、WalkieTalkieActivity
A、SipManager.newInstance()-->此方法中首先判断context是否支持SIP API,若支持则new SipManager。SipManager构造函数中,实例化了一个ISIPService(运用的公式:
IBinder b =ServiceManager.getService(Context.SIP_SERVICE); //获取系统相应的服务
ISipService service = ISipService.Stub.asInterface(bIBinder);)
上面这两句代码其实是使用了AIDL,就以SipService为例,步骤如下
Service端
1、编写aidl文件:ISipService.aidl,并定义使用的接口(就等同于interface一样)
2、使用makefile生成与之同名的JAVA文件,SipService.java,此类继承extends ISipService.Stub并实现接口定义的方法或者在SipService extends Service,并代码中加入
ISipService.stub sipImpl = new ISipService.stub(){
//实现其接口方法,在SipService.java中是实现了一个名为start()的方法,里面有句是ServiceManager.addService("sip",newSipService(context));表示SipService已经交给ServiceManager统一管理了
}
Client端
一(以SIPService为例)
1、而在需要用到SipService时,也就是我们构造SipManager的时候,就通过ServiceManager.getService(Context.SIP_SERVICE)获得SIP的服务(类型为IBinder)
2、并调用 ISipService.Stub.asInterface(IBinder);去获取一个SipService实例(前提是该Service一定是通过ServiceManager.addService的方式添加进去管理的,这样才能找到此Service)
二(以普通Activity为例)
1、利用Intent intent = new Intent(Activity.this,SipService.class);-->bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);来绑定SERVICE,在serviceConnection的onServiceConnected方法中,使用IService.stub.asIntentface(IBinder);来获取实例。
B、SipManager创建好后,先从SharedPreference中获取username,domain及pwd,如果第一次进来没有设置这些的话则需要先创建账户,这里用EditTextPreference来保存用户信息,好处是当填写信息并返回后,EditTextPreference会自动将值放入SharedPreference中。我们假设username="woody";domain="192.168.12.30";pwd="910913"。
C、这时,我们的SipManager以及用户信息已经设定好了,接下来使用了这句SipProfile.Builder builder = new SipProfile.Builder(username, domain);我们去看看SipProfile.Builder中做了些什么:
SipURI mUri =mAddressFactory.createSipURI(username,serverDomain);
SipProfile mProfile.mDomain=serverDomain; //设置domain
(在mAddressFactory.createSipURl方法中,我选取了一些核心代码)
StringBuffer uriString=new StringBuffer("sip:");
uriString.append(user);
uriString.append("@");
//if host is an IPv6 string we should enclose it in sq brackets
if(host.indexOf(':') !=host.lastIndexOf(':')&&host.trim().charAt(0) !='[')
host='['+host+']';
uriString.append(host);
StringMsgParser smp=new StringMsgParser();
SipUrl sipUri=smp.parseSIPUrl(uriString.toString());
return sipUri;
从以上代码可以看出其实就是在Format SipURL罢了,里面多加了个if host为IPV6的判断(IPv4为为32位,十进制;IPv6为128位,16进制)。urlString最后为"sip:woody@192.168.12.30",smp.parseSIPUrl()方法中,有关于是如何parse的就不做阐述了,总之最后返回了一个SipUri
D、接下来就是SipProfile sipProfile = SipProfile.Builder.build(); //返回一个SipProfile object
在SipProfile.Builder.build()中,设置了sipProfile的pwd值,删除了之前SipUrl对象里的password(mUri.setUserPassword(null);)、将sipProfile的address属性设置为AddressImpl类型的对象值、调用AddressFactory.createURI返回一个SipUri,并sipProfile.mProxyAddress=sipUri.getHost();
E、创建PendingIntent对象:(Intent与PendingIntent区别在于Intent是及时启动,而PendingIntent是不立刻反应,在特定的情况或通知下才启动,适用于AlertClock等)
Intent i = new Intent();
i.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
F、SipManager.open(sipProfile,PendingIntent,null); //(实际是SIPService在做操作)设置localSIPProfile的callingID-->建立SIP连接(算是注册至SIP Server)-->打开receiveCall
其中建立SIP连接,最后能追溯到是在SipSessionGroup.java的reset()方法中通过是注册服务器实现的,
注册服务器的步骤为:
(1)设置服务器的属性,例如服务器的地址(IP_ADDRESS_PROP)、栈名(javax.sip.STACK_NAME)、发出去的路径(localProfile中的javax.sip.OUTBOUND_PROXY)、线程池的大小(gov.nist.javax.sip.THREAD_POOL_SIZE)等,并且将这些属性加载到服务器中.
(2)通过SipFactory的静态方法取得一个实例,然后通过SipFactory实例sipfactory
(3)创建一个SipStack实例sipstack(这一步获得IP_ADDRESS_PROP,String address = Properties.getProperty("javax.sip.IP_ADDRESS");)
(4)用sipstack创建一个SipProvider实例sipProvider
(5)注册SipListener
G、A~F步骤都是在做准备工作,大致的步骤如下:new SIPService-->new SIPManager-->设定用户信息-->new SIPURI-->new SIPProfile-->new PendingIntent-->set sipProfile callingID-->(if profile.getAutoRegistation)open toReceiveCalls-->register SipService 现在是call someone~呼叫的工作是SipAudioCall类来完成(可用sipManager.makeAudioCall或takeAudioCall来实例化,SipAudioCall.startAudio时需要 RECORD_AUDIO, ACCESS_WIFI_STATE, and WAKE_LOCK permissions,setSpeakerMode() 时需要MODIFY_AUDIO_SETTINGS permission)
【1】当需要呼叫时,使用sipManager.makeAudioCall(String localProfileURI, String peerProfileURI, SipAudioCall.listener,int timeout);来创建一个SipAudioCall,其中timeout以seconds为单位,过了timeout表示打电话超时。需要打给别人时使用makeAudioCall创建,接听电话用takeAudioCall来创建sipAudioCall
【2】SipAudioCall中有一个嵌套的class:SipAudioCall.Listener(此类主要用于监听SIP CALL,when[呼叫电话 or 接听电话])
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
@Override
public void onCallEstablished(SipAudioCall call) { //呼叫建立
call.startAudio(); //启动音频
call.setSpeakerMode(true); //调整为可讲话模式
call.toggleMute(); //触发无声
updateStatus(call);
}
};
SipAudioCall call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);
(以上例子为makeAudioCall)
【3】我们看看makeAudioCall()方法(makeAudioCall requires 2 sipProfile):
SipAudioCall call =new SipAudioCall(mContext, localProfile);
call.setListener(listener); //这两句很简单就是创建一个local的sipAudioCall
SipSession s = createSipSession(localProfile, null); -->mSipService.createSession(localProfile, null);// sipService来创建session,并保存在SipSessionGroupExt中
call.makeCall(peerProfile,s,null); //这句就是呼叫,最后追溯到实际是SipSession.makecall
总结:在发起通话中
首先是创建SipAudioCall.listener,以便监听对话建立和对话结束,然后做相应的操作,然后是SipManager.makeAudioCall(localAdd,llistener,XXXX),在makeAudioCall方法中
A、创建一个sipAudioCall(localProfile)
B、创建SipSession以建立起会话
C、SipSession.makeCall(peerProfile,XXXX); //SipSession呼叫远程profile
【4】关于接电话道理都差不多,takeAudioCall通过之前设置的callingID来查找mSipService.getPendingSession(callId);来获得SipSession。并创建SipAudioCall,然后attachCall就算接受电话了。
三、总结
1、VOIP服务位于android.net.sip包中,关键类为SipManager。需要用到的permission列表,其中后面三个为使用WIFI获取IP地址所需要用到的权限:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.USE_SIP"/>
<uses-feature android:name = "android.hardware.sip.voip" android:required = "true"/>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />