android voip你选哪一个 SipDroid,IMSDroid,CSipsimple,Linphone,webrtc?-Android开发进阶&经验分享-eoe Android开发者社区_Android开发论坛 - Powered by Discuz!
最新要做一个移动端视频通话软件,大致看了下现有的开源软件
一) sipdroid
1)架构
sip协议栈使用JAVA实现,音频Codec使用skype的silk(Silk编解码是Skype向第三方开发人员和硬件制造商提供免版税认证(RF)的Silk宽带音频编码器)实现。NAT传输支持stun server.
2)优缺点:
NAT方面只支持STUN,无ICE框架,如需要完全实现P2P视频通话需要实现符合ICE标准的客户端,音频方面没看到AEC等技术,视频方面还不是太完善,目前只看到调用的是系统自带的MediaRecorder,并没有自己的第三方音视频编解码库。
3)实际测试:
基于sipdroid架构的话,我们要做的工作会比较多,(ICE支持,添加回音消除,NetEQ等gips音频技术,添加视频硬件编解码codec.),所以就不做测试了。
二) imsdroid
1)架构:
基于doubango(Doubango 是一个基于3GPP IMS/RCS 并能用于嵌入式和桌面系统的开源框架。该框架使用ANSCI-C编写,具有很好的可移植性。并且已经被设计成非常轻便且能有效的工作在低内存和低处理能力的嵌入式系统上。苹果系统上的idoubs功能就是基于此框架编写) .音视频编码格式大部分都支持(H264(video),VP8(video),iLBC(audio),PCMA,PCMU,G722,G729)。NAT支持ICE(stun+turn)
2)效果实测
测试环境:公司局域网内两台机器互通,服务器走外网sip2sip
音频质量可以,但是AEC打开了还是有点回音(应该可以修复)。视频马赛克比较严重,延迟1秒左右。
3)优缺点
imsdroid目前来说还是算比较全面的,包括音视频编解码,传输(RTSP,ICE),音频处理技术等都有涉猎。doubango使用了webrtc的AEC技术,但是其调用webrtc部分没有开源,是用的编译出来的webrtc的库。如果要改善音频的话不太方便,Demo的音频效果可以,视频效果还是不太理想。
三)csipsimple
1)sip协议栈用的是pjsip,音视频编解码用到的第三方库有ffmpeg(video),silk(audio),webrtc.默认使用了webrtc的回声算法。支持ICE协议。
2)优缺点:
csipsimple架构比较清晰,sip协议由C实现,java通过JNI调用,SIP协议这一块会比较高效。其VOIP各个功能也都具备,包括NAT传输,音视频编解码。并且该项目跟进新技术比较快,官方活跃程度也比较高。如果做二次开发可以推荐这个。
3)实测效果
测试环境:公司局域网内两台机器互通,服务器走外网sip2sip
音频质量可以,无明显回音,视频需要下插件,马赛克比imsdroid更严重。
四)Linphone
这个是老牌的sip,支持平台广泛 windows, mac,ios,android,linux,技术会比较成熟。但是据玩过的同事说linphone在Android上的bug有点多,由于其代码实在庞大,所以我暂时放弃考虑Linphone.不过如果谁有跨平台的需要,可以考虑Linphone或者imsdroid和下面的webrtc.。。。好像现在开源软件都跨平台了。。。
五) webrtc
imsdroid,csipsimple,linphone都想法设法调用webrtc的音频技术,本人也测试过Android端的webrtc内网视频通话,效果比较满意。但是要把webrtc做成一个移动端的IM软件的话还有一些路要走,不过webrtc基本技术都已经有了,包括p2p传输,音视频codec,音频处理技术。不过其因为目前仅支持VP8的视频编码格式(QQ也是)想做高清视频通话的要注意了。VP8在移动端的硬件编解码支持的平台没几个(RK可以支持VP8硬件编解码)。不过webrtc代码里看到可以使用外部codec,这个还是有希望调到H264的。
总结:sipdroid比较轻量级,着重基于java开发(音频codec除外),由于其音视频编码以及P2P传输这一块略显不足,不太好做定制化开发和优化。imsdroid,遗憾就是直接调用webrtc的库,而最近webrtc更新的比较频繁,开发比较活跃。如果要自己在imsdroid上更新webrtc担心兼容性问题,希望imsdroid可以直接把需要的webrtc相关源码包进去。csipsimple的话,都是围绕pjsip的,webrtc等都是以pjsip插件形式扩充的,类似gstreamer. webrtc如果有技术实力的开发公司个人还是觉得可以选择这个来做,一个是google的原因,一个是其视频通话相关关键技术都比较成熟的原因。个人觉得如果能做出来,效果会不错的。
以上仅是个人观点,每个项目需求不一样,选择可能也不一样。欢迎大家跟贴讨论交流或者QQ交流
QQ34280027
android 视频通话 项目 源码 - android大牛MrJing 活动中心 - 博客频道 - CSDN.NET
几个开源的视频会议、SIP服务器:
Telepresence:https://code.google.com/p/telepresence/
Yate:http://yate.null.ro/pmwiki/
Doubango:http://www.cnblogs.com/DreamSea-for-Jimmy/archive/2011/07/28/2119877.html
一、开源voip有哪些
SIPDroid、linphone、imsdroid
SIPDroid:纯java语言开发
Linphone:基于多个平台,但android下的bug较多,很难正常的通话。
Imsdroid:底层基于doubango的开源代码,更新比较及时.
Linphone和Imsdroid的底层均是c语言,支持的平台比较广泛.
二、源码如何获取
Linphone:http://www.linphone.org/需安装git工具.
不知道是否因为git工具的问题,经常没下午便断开,需获取多次,才能获取到完整的代码.
Imsdroid:这个首先必须安装svn.需先下载doubango的源码,然后再下载Imsdroid的源码. Imsdroid的源码位置: http://code.google.com/p/imsdroid/source/checkout, doubango的源码位置:http://code.google.com/p/doubango/source/checkout.
三、编译重需注意;
Linphone:编译过程还需要下载其他的内容,可以直接复制网址到ie中进行下载.
如果你是在windows下使用cygwin,最好链接的时候会出现一个致命的错误,那就是argument list too long,这种情况下,最好直接放到linux下去编译,该问题便可以解决.升级cygwin的版本也很难解决该问题.
Linphone的java工程要求sdk为2.3版本,对我们这种在公司网络不好的人来说,这是最悲催的事了.
Imsdroid:分为两部分:doubango和imsdroid的编译.
Doubango:windows下编译会有一大堆的错误,还是果断放弃windows,转到linux下编译好了.但建议最好编2.0版本,2.0的编译方法需要到wiki中查找, 参考http://code.google.com/p/imsdroid/wiki/Building_IMSDroid_v2_x这个网页.最好生成一个动态库tinyWRAP.so.
Imsdroid的编译:最后要生成apk文件,必须首先编译android-ngn-stack工程,该工程编译成功后,会生成jar文件,供imsdroid工程使用.
Oracle 数据库隔离级别,特性,问题和解决方法 - 1-2-3 - 博客园
Oracle的序列化(serializable)隔离级别
序列化,顾名思义,是让并发的事务感觉上是一个挨一个地串行执行的。之所以说是“感觉上”,是因为当2个事务并发时,Oracle并不会阻塞其中一个事务去等待另一个事务执行完毕再执行,而是仍然让2个事务同时并行,那么如何能“感觉”是串行的呢?请看下图的实验。
用户B的事务因为指定了serializable隔离级别,所以虽然在查询费用明细表之前,用户A提交了对费用明细表的更改,但是因为用户A提交的更改是在用户B的事务开始之后才提交的,所以这个更改对用户B的事务不可见。也就是说,用户B的事务开始之后,其它事务提交的更改都不会再影响事务内的查询结果,这样感觉上用户A的事务好像是在用户B的事务结束之后才执行的似的。这本来是非常好的一个特性,极大地提高了并行性,但是也会造成问题。
问题1:Oracle的这种“假串行”会让严格依赖于时间的程序产生混乱。
请看下图这个例子,对费用结算的例子稍稍做了一点改动。
程序员的本意是统计2012-3-4这天从零点至运行程序之时的费用总额。如果他以为 Oracle 的 serializable 会像 C# 的 lock 一样阻塞其它事务的话,就会对结果非常吃惊:在2012-3-4 0:00 ~ 2012-3-4 10:02 实际有3条费用明细,总额为20+30+100=150,而不是用户B的事务统计得出的50。
问题2:ORA-08177 Can't serialize access for this transaction (无法序列化访问)错误。
如果你使用了 serialize 隔离级别,没准你的客户会经常抱怨这个随机出现的错误。兄弟,你并不孤独!
导致这个错误的原因有2个:
(1) 两个事务同时更新了同一条数据。你可以这样重现这个错误:事务B开始(使用serialize 隔离级别) => 事务A开始,更新 表1.RowA 但不提交 => 事务B更新表1.RowA,因为行锁定而被阻塞 => 事务A提交 => 事务B报 ORA-08177 错误。
(2) 事务所更新的表的 initrans 参数太小。Oracle 官方文档的说法是,如果使用了 serialize 隔离级别,表的 initrans 参数最小要设置成3(默认是1)。
alter table 费用明细表 initrans 3;
原文:“Oracle Database stores control information in each data block to manage access by concurrent transactions. Therefore, if you set the transaction isolation level to SERIALIZABLE, then you must use the ALTER TABLE command to set INITRANS to at least 3. This parameter causes Oracle Database to allocate sufficient storage in each block to record the history of recent transactions that accessed the block. Higher values should be used for tables that will undergo many transactions updating the same blocks.”
注意,人家说的是“最小是3”。我用自己笔记本里的 32 位 Oracle10g 测试的结果是设置成 3 也会频繁地报 ORA-08177 错误。后来改成5 和 10,都不行。改成50,终于不报错了。但是都说了这个错误是随机的,有时候3也没问题的——反过来说,设置成50也未必保险。坑爹啊!真坑爹!!这就像菜谱里面写的“放入适量的油……”,他喵的到底多少算是“适量”啊?!!!
有兴趣的读者可以使用下图的语句实际测试一下。
我的建议是,还是尽量不要用 serialize 隔离级别吧,用户是不会理解什么叫“无法序列化访问”的,他只会觉得你的“XX功能会随机地不好用”倒是真的。稍后我们再简单讨论一下不用 serialize 隔离级别如何避免幻读。现在先来看一下 Oracle 官方文档建议的适合使用 serialize 隔离级别的3种情况。
(1) With large databases and short transactions that update only a fewrows(大数据库、只更新几条数据的短事务)
(2) Where the chance that two concurrent transactions will modify thesame rows is relatively low(2个并发事务更新同一条数据的几率不大)
(3) Where relatively long-running transactions are primarily read only(相对运行时间较长的事务主要用来读取数据)
使用默认的 read committed 隔离级别,如何避免幻读产生的问题
使用默认的 read committed 隔离级别,如何编写程序才能避免幻读产生的问题呢?首先,无论是“不可重现的读取(nonrepeatable read)”还是“幻读(phantom read)”,都是因为程序反复读取数据产生的。所以首先需要做的是,在一个事务里确保只读取数据一次。最好用C#而不是存储过程实现业务逻辑,这样很容易做到只读取一次,然后把结果存放到IList或IDictionary里。比较难办的是需要更新数据的情况。回顾一下前面所举的幻读的例子。
事务B使用相同的条件进行了2次查询/筛选,一次是为了向费用结算表插入汇总数据,一次为了确定对费用明细表的更新范围。在这两次筛选之间,事务A提交了一条新的费用明细数据,导致两次筛选的结果不一致。要避免这个问题,还是要贯彻“只读取一次”的原则,或者更广义地说,是“只确定一次筛选范围”。大致有2种方法。
<法一> 可以先把符合条件的费用明细读取出来保存到一个列表里,然后无论统计还是更新,都局限于这个列表里的数据。下面的C#代码与上图的功能相同,但是没有幻读的问题。
// 用户B的事务开始
IList<费用明细> chargeList = 费用明细Repository.获取未结算列表();
费用结算 balance = new 费用结算
{
总金额 = chargeList.Sum(t => t.金额),
结算编号 = "J122"
};
费用结算Repository.Save(balance);
// 这时候用户A提交了一条新的费用明细,不过没关系
foreach(费用明细 charge in chargeList)
{
charge.是否已结算 = 1;
charge.结算编号 = "J122";
费用明细Repository.Update(charge);
}
这个方法的缺点是要对 chargeList 里的每个实体 Update 一次,如果数据量较大可能会有性能问题。这时候可以用<法二>。
注 本文为了表述的方便使用了中文和英文混杂的代码,实际编程的时候不要这样做。
<法二> 使用事务B独有的方法标识出操作数据的范围。
注 虽然上图是用SQL语句来演示的,使用C#(实体+ORM)同样可以用这种方法。
严格依赖时间的程序
严格来说这并不是幻读造成的问题——事务A还没提交呢。这种设计十分危险,无论使用 read committed 还是 serializable 隔离级别都不足以避免并发造成的不一致,应该尽量避免这样的设计。依赖时间很危险,因为系统时间是随时可能被系统管理员更改的,更别提有些国家和地区会实行夏时制,想想看,事务B提交了之后,系统时间被回拨了1小时!
然而世事往往不尽如人意,你可能不幸遇到了这样一个遗留系统,或者用户有很多其它的业务或与你交互的系统严格依赖于时间而逼得你不得不这么做的时候,该怎么办呢?
<法一> 在业务逻辑层面,可以把用户B和用户A的两个方法使用C#提供的线程同步技术串行化——理论上行的通,但是操作费用明细实体的方法那么多,很容易有所遗漏。
<法二> 在Repository层面,为费用明细实体设置一个令牌,并且可以设置是否进入令牌模式。在令牌模式下,费用明细Repository里面的所有持久化操作都必须拿到令牌才能操作,拿不到令牌直接抛异常。平时的业务操作都在非令牌模式下工作。在用户B想要进行结算操作时,事务开始之后,马上设置成令牌模式,然后获取令牌,这样就能确保此时只有用户B才能操作费用明细表了。此法虽然并发性很差,但是既简单又保险。而且很多时候像结算这样的操作一个月(或一天)只进行一次,并发性差一些也可以忍受。值得注意的是下面这种情况。
虽然发生的概率不高,但是让令牌法彻底失效了。综合考虑系统时间被管理员改变的可能性,仅仅在结算事务里独占令牌也是不够的,还必须在费用明细Repository.Save()方法里验证费用明细.创建时间必须大于最近一次的结算时间。