SIPDroid.docx
- 文档编号:9752247
- 上传时间:2023-05-21
- 格式:DOCX
- 页数:21
- 大小:172.80KB
SIPDroid.docx
《SIPDroid.docx》由会员分享,可在线阅读,更多相关《SIPDroid.docx(21页珍藏版)》请在冰点文库上搜索。
SIPDroid
AndroidSIPdroidProjectSharing
May23
2011
Warning:
Ifyouhaveanyquestions,adviceorsomethingelse,pleaseletteamknow.
FightTeam
怎么学习androidSipdroid开源代码?
Sipdroid目前有24个包,140多个java文件.首先学习Sipdroid,至少得明白Sipdroid是怎么玩的,实现的主要功能是什么,具体的流程操作是怎么执行的。
先整理下下面的问题:
一.Sipdroid的数据流程怎么发送的?
参考文档:
http:
//www.shouyanwang.org/thread-5-1-1.html
二.Sipdroid中采用的是什么协议?
这点非常的重要,因为Sipdroid采用的是RFC3261协议,大家看了RFC3261协议后,你就会明白,Sipdroid中对于Message的封装是如何完成,那么Message的封装和生成这块所涉及到得设计模式和代码,你基本就可以弄明白
参考文档:
http:
//www.shouyanwang.org/thread-3-1-1.html
三.分块来弄Sipdroid
首先Sipdroid的架构真是设计的是非常的人性化以及牛X,为什么呢,功能块是完全独立和分开的,高内聚低耦合,Sipdroid本身来说就像一座非常难以攻克的堡垒,但是咱们只要一块一块的攻,不久就发现整做城堡都被搞定了。
一般来说,应该这么做:
1.研究注册流程
参考文档:
http:
//www.shouyanwang.org/thread-35-1-1.html
2.研究会话邀请流程
3.视频通话通话流程
4.整理Sipdroid的架构
5.提取有用信息,比如视频和声音的编解码库,协议的封装和设计模式等
Sipdroid流程详细分析
1.SipDroid模块简单分析
UI层,负责界面显示模块和界面时间传递
Engine层:
软件核心处理层,启动各种服务,初始化软件参数。
处理各种UI时间,维持配置文件信息,保存全局属性变量。
其中包括UserAgenProfile(用户配置文件属性),UserAgent(用户事件处理),SipdroidEngine(核心处理,所有的UI的事件,参数设计,服务的启动都由此文件调度),RegisterAgent(注册服务处理)
Sip层:
提供所有sip消息模型,所有sip消息的处理流程,包括发送,接收,封装,解码等等
网络传输:
提供音频,视频信息的处理,此模块会对音频视频进行即时编码解码,同时发送数据。
同时还提供JSTNNAT透传技术。
2.SipDroid流程分析:
拨号:
拨号请求由UI通过Receiver广播信息交给SipDroidEngine处理,在SipDroidEngine做一些验证,然后交给UserAgine处理。
其中call(Stringtarget_url,booleansend_anonymous)为判断是否匿名拨号再此方法中,会创建一个ExtendedCall对象,以提供给sip协议栈使用,然后调用ExtendedCall的call方法处理,之后由ExtendedCall的call,调用ExtendedInviteDialog来发送invite请求。
由InviteDialog执行具体的invite调用InviteTransactionClient的request方法,最后由InviteTransactionClient发送request请求,在InviteTransactionClient中会通过SipProvider,来发送消息,并打开对端口监听,来收sip消息。
发送消息主要有(UDP传输UdpTransport TCP传输TcpTransport)
来电:
在启动程序的时候会通过SipDroidEngine会根据配置,创建一个Provider,这里用到udp传输,创建一个Udpprovider,udpprover是一个Thread,创建的时候就会启动线程,开始监听收到的信息,当受到信息后,通过onServiceTerminated方法,把对象传出到UdpTransport,由UdpTransport处理,再通过onTransportTerminated方法传出到SipProvider对象,最后将在SipProvider的processReceivedMessage方法中处理收到的消息,最后从listeners(map)中取出相应的listener,最后通过相应的listener中的OnReceiveMessage()来处理具体Sip请求
Sipdroid会话邀请流程
(一)
Sipdroid会话流程图:
图片比较直观,但是表述却不够详细,下面咱们详细分析下流程:
会话邀请所涉及到得类:
SipdroidEngine(call)-UserAgent(call)-ExtendedCall(call) -InviteDialog(invite)
左边的代表涉及到的类,右边代表涉及到的核心方法,从左到右进行观察,左边的类都有一个右边类型的参数作为自己的成员函数,就是SipdroidEngine有一个成员函数ua,这个ua是UserAgent类型的。
。
。
。
InviteDialog中的invite函数所做的事情也是非常的简单,生成会话邀请的message然后通过SipProvider发送出去就行了,那么发送完毕后,怎么实现对发送结果的监听呢?
其实自己猜测一下也猜测到服务器返回数据会什么类型的?
1、等待对方应答中
2.对方已经应答,进入双边通话模式中,同时手机这边开始声音和视频的采集.(声音和视频的采集,这个是核心中的核心哦,马上就要弄到这块了,兴奋啊)
3.超时,对方无应答.
在二的分析中,咱们用倒推的方法来分析下客户端在接受到服务器的返回后,传递到了哪里去进行会话邀请的结果了,客户端是怎么实现的.
Sipdroid会话邀请流程
(二)
这里咱们要弄明白的是,Sipdroid会话邀请的结果是在哪里进行监听的,以及这种效果是怎么实现的?
发送消息统一是由Sipdroid的sendMessage来进行发送的,然后返回的数据咱们可以在Sipdroid的OnReceiveMessage中来进行获取。
在Sipdroid注册结果的监听:
http:
//www.shouyanwang.org/thread-44-1-1.html这篇文章中,咱们分析了下,首先会话的类型有很多种,注册会话,邀请会话,通话会话等等,因此在OnReceiveMessage中会对当前进行的会话进行判断,根据当前的会话ID,判断出当前具体的会话类型,然后具体的会话类型通过调用自己的成员函数(会话接口对象的接口方法)将数据会话接口对象.
那么分析就简单了,倒推下:
1.邀请会话类是谁?
2.邀请会话类得会话接口是哪个,邀请会话类会在获取到返回的数据后将获得到得数据传递给会话接口的接口方法中
3.分析会话接口中的方法是怎么处理邀请回话类返回的数据的?
只要咱们这样分析,咱们就可以倒推出最终数据是怎么处理的,处理数据的核心其实还是更新UI界面和进行逻辑判断,所以最终的处理必须是距离UI界面近的类。
会话邀请类是:
InviteTransactionClientinvite_tc=newInviteTransactionClient(sip_provider,invite_req,this);
nvite_tc.request();
SipPorvider在获取到数据后是怎么传给会话邀请类得?
每个具体的会话类都会继承一个抽象的会话类,这个抽象的会话类继承了SipProviderListener,在SipProvider获得message后,在OnReceiverMessage中,会通过执行SipProviderListener的接口方法将数据传给是实现了此接口的类,在会话邀请类中也就会传递给具体的会话类InviteTransaction.
每一个具体类在初始化的时候,是必须有SipProvider作为参数的,然后在通过SipProvider的addSipProviderListener(id,SipProvierListner)指定会话类型和会话接口,还有SipProvider是唯一和独立的,因此一个会话中,只可能存在一种会话类型.
InviteTransactionClient在onReceiveMessage会将数据传递给transaction_listener,transaction_listener其实就是InviteDialog,InviteDialog实现了TransactionClientListener,并在InviteTransactionClinet的时候传递进去了,所以数据都是按照这样的逻辑往上传的,剩下的分析就非常简单了,大家自己分析吧。
所以最终的数据还是会回到UserAgent里面CallListenerAdapter接口方法里面。
这个方法还挺巧的,谁发送的请求最后就由谁最终来处理这个返回的结果,然后呢,SipdroidEngined就是这些核心类用来交互的一个地儿,然后咱们在启动的Actiivity里面就只管调用SipdroidEngine提供的方法来控制指令就成了,牛X的框架啊。
RegisterAgent最先发送注册请求,最后的注册结果也得RegisterAgent来处理。
UserAgent最先发出会话邀请请求,最后的邀请结果也得UserAget来处理.
Sipdroid中像服务器注册是如何实现的
(一)
关于Sipdroid是如何实现像服务器注册的?
首先告诉大家代码块在哪里,注册的核心在RegisterAgent类中的函数register(inttime)中,注册的核心是:
1.//Createmessagere(modifiedbymandrajg)
2.Messagereq=MessageFactory.createRegisterRequest(sip_provider,
3.target,target,newNameAddress(user_profile.contact_url),qvalue,icsi);
4.
5.req.setExpiresHeader(newExpiresHeader(String.valueOf(expire_time)));
注册稍微简单一点,因为只是需要客户端和服务器进行绑定就行了,注册在SIP协议中称作登记服务,再向服务提供商进行注册的时候,服务提供商都会给我们一个URL,这个URL在Sipdroid中被封装在SipURL中的,这个URL写的格式如下:
sip:
*******************.cn,用户名+主机名。
登陆服务过程中的具体流程如下:
程序启动便自动进行初始化,在初始化的过程中,每隔一段的时间,客户端这边就要发送Register信息给服务器,Register中的信息包含了服务提供商分配给当前用户的SIPURI(通俗点说,SIPURI就是客户端的标识,这个标识是必须是唯一的)
服务器通过获得当前用户的URI便可以绑定这个用户,然后写到一个数据库中,在SIP协议中,这个叫做定位服务(locationserver)
发送的请求的格式如下:
F1REGISTERBob->Registrar
REGISTERsip:
SIP/2.0
Via:
SIP/2.0/UDP:
5060;branch=z9hG4bKnashds7
Max-Forwards:
70
To:
Bob **************> From: Bob **************>;tag=456248 Call-ID: 843817637684230@998sdasdh09 CSeq: 1826REGISTER Contact: *********.2.4> Expires: 7200 Content-Length: 0 注册会在2小时后超时。 注册服务器回应一个200OK,返回的信息包含如下: F2200OKRegistar->Bob SIP/2.0200OK Via: SIP/2.0/UDP: 5060;branch=z9hG4bKnashds7 ;received=192.0.2.4 To: Bob **************>;tag=2493k59kd From: Bob **************>;tag=456248 Call-ID: 843817637684230@998sdasdh09 CSeq: 1826REGISTER Contact: *********.2.4> Expires: 7200 Content-Length: 0 这里面涉及到很多参数,但是在RFC3261中都有详细的介绍。 第二篇将给大家介绍下,发送的注册消息体里面的每个参数所代表的意义. Sipdroid注册 (二)-Sipdroid注册SIP消息分析 发送注册的message的结构体如下: F1REGISTERBob->Registrar REGISTERsip: SIP/2.0 Via: SIP/2.0/UDP: 5060;branch=z9hG4bKnashds7 Max-Forwards: 70 To: Bob **************> From: Bob **************>;tag=456248 Call-ID: 843817637684230@998sdasdh09 CSeq: 1826REGISTER Contact: *********.2.4> Expires: 7200 Content-Length: 0 下面咱们分析下,这里面的数据? 里面的数据在RFC3261协议中已经有很清楚的说明了,只是比较的分散. 上面的数据称为: SIP消息,SIP协议是基于文本的协议,使用UTF-8字符集。 SIP消息的大致组成是按照下面的格式进行的. 一般消息= 起始行 *消息包头 CRLF //crlf也就是回车换行的意思 [消息正文] 起始行= 请求行/状态行 需要注意的是,每一行结束后都要加回车换行\r\n,并且回车换行只允许加到末尾,其余的位置不允许出现回车换行 请求分析: Request-Line=MethodSPRequest-URISPSIP-VERSIONCRLF //SP代表空格 这个是请求行的格式,Method定义了6中方法,REGISTER用于登记联系信息,INVITE,ACK,CANCEL用于建立会话,BYE用于结束会话 Request-URI就是注册商分配给你的唯一的标识符,服务器需要这个数据来于你进行绑定, SIP-VERSION: 请求和应答消息都包含的当前所有的SIP版本,一般写SIP/2.0就行了 后面的那些参数: TOFROMCseqCall-ID这些字段在SIP消息中被称为头域,这些头域包含了路由用的核心信息,比如消息地址,事物的唯一标志等 To RFC3261中的详细解释在8.1.1.2章节 To头域是第一个并且也是最先指定请求的逻辑接受地,或者是这个请求的用户或者资源的address-of-record(这个语句解释的有点抽象). To头域的写法 SP表示空格) 姓名(可用可不用)SPSIPURI example: To: 523851253 ********************.cn> From 详细的说明文档请参加RFC3261 8.1.1.3章节 Fromm头域包含了请求发起者的逻辑标志,可以是用户的address-of-record. From头域的主要作用是用来实现对请求的检查,同时让服务器选择一个规则对请求进行处理,同样From也可以包含一个请求人的姓名,值得注意的是,From还必须包含一个TAG,这个tag是UAC(用户代理客户端,Sipdroid中其实也就是sipdroid程序给产生的)自动给你产生的,tag的详细描述在RFC3261 19.3章节. From格式: From: 姓名(可有可无)SP ********************>;tag=a48sCTLF(回车换行) RFC3261协议中对于Call-ID写的已经是非常非常详细了,直接贴出来给大家看: Call-ID是一个在一系列消息中,区分一组消息的唯一标志。 在对话中的任一UA的所有请求和所有应答的Call-ID必须一致。 在UA的每次注册中,都应该是一样的。 在会话外的时候,UAC发起一个新的请求,这个Call-ID头域必须由UAC产生一个全局(在时间和空间上都是)唯一的Call-ID,除非是请求头的方法(method)指明了别的产生方式。 所有的SIPUA都必须保证自己产生的Call-ID不会和其他UA产生的Call-ID重复。 注意,如果是请求的重新尝试,则重新尝试的请求不被当作一个新的请求,所以不需要新的Call-ID(重新尝试的请求例如: 认证冲突等等)。 (见8.1.3.5) 我们强烈建议用密码乱序随机串(RFC1750[12])来产生Call-ID。 实现中,可以用类似”localid@host”这样的格式产生。 Call-ID是大小写敏感的,并且通过简单字节/字节的来进行比较。 采用密码乱序随机串可以降低会话被窃听的机会,并且降低Call-ID重复的冲突。 不规定或者要求使用用户界面来选择输入Call-ID头域的值。 参见20.8节 Cseq 组成格式: 一系列的顺序号码+方法 Cseq头域是用来区分和做位事务的顺序使用的。 他由一个方法(method)和一系列的顺序号码组成。 方法(method)必须和请求的方法一致。 对于对话外的非REGISTER请求来说,顺序号码可以是任意的。 这个顺序号码必须可以由32位的无符号整数表达,必须小于2^31。 只要遵循了上述指导方针,客户端可以用任意的方法来产生这个Cseq头域。 12.2.1.1节讲述了在对话中如何创建Cseq 例子: Cseq: 4711INVITE Sipdroid注册(三)-注册返回结果的监听 看Sipdroid的源码,发送注册message后,是如何实现对注册返回结果进行监听的? Sipdroid的数据发送流程是这样的: http: //www.shouyanwang.org/thread-5-1-1.html 先直接给大家说下结果: 对注册结果的监听是通过RegisterAgent来进行监听的,因为RegisterAgent实现了TransactionClientListener接口,通过 /** *WhentheTransactionClientgoesintothe"Completed"statereceivinga *2xxresponse */ publicvoidonTransSuccessResponse(TransactionClienttc,Messageresp); 函数即可实现对返回结果的监听。 那么按照Sipdroid的数据发送流程,最终获取到得结果是会传递到SipProvider中的onReceiverMessage()接口方法中,那么如何来实现将OnReceiverMessage中获取到的结果传递到RegisterAgent中呢? 这里其实还真的挺佩服涉及Sipdroid架构的哥们的,大量的运用回调和接口来进行数据的转发. 注册的流程是这样的: RegisterAgent--register(inttime) register函数主要干两件事情,一是生成注册消息的message,另一个就是发送这个message, message可以看http: //www.shouyanwang.org/thread-35-1-1.html这篇文章 message发送成功后,那么就得发送,发送是通过: //TransactionClientt t=newTransactionClient(sip_provider,req,this,30000); t.request(); 来完成的,request函数中有两行代码非常重要: sip_provider.addSipProviderListener(transaction_id,this); connection_id=sip_provider.sendMessage(request); sip_provider发送消息后,通过onReceiveMessage来接受消息,接受消息后就会进行一件事情的判断,通过判断发送message的transaction_id来判断此前发送的请求是用来注册,还是用来进行会要的邀请呢? transaction_id其实就是一个标识,标识会话类型的,会话类型包括: 注册,通话请求等等,然后在onReceiveMessage中进行判断。 SipProvider中有如下的一个参数: /**Listofproviderlisteners*/ Hashtable listeners里面含有的对应关系为会话标识符----会话接口,比如注册过程就是注册会话标识符对应注册会话接口,所以只要是会话类型那么必然要实现会话接口SiproviderListener,会话有很多种,比如注册会话,通话会话,视频会话,那么Sipdroid的开发者就提取了他们的共同点,封装成了一个抽象的会话类型: publicabstractclassTransactionimplementsSipProviderListener,TimerListener; 具体的会话都必须继承Transaction,Transaction默认的已经继承了SipProviderListener。 所以呢,具体的数据最终会返回到具体的会话类中,注册的会话类是: TransactionClient,在TransactionClient中通过OnReceiverMessage就可以获得服务器返回的注册应答的数据,那么如果TransactionClient如何将应答的数据返回给RegisterAgent呢? 在TransactionClient初始化的时候 t=newTransactionClient(sip_provider,req,RegisterAgent.this,30000); RegisterAgent将自己作为Transacti
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- SIPDroid
![提示](https://static.bingdoc.com/images/bang_tan.gif)