Android 开发 voip/sip 程序

首先说明一下相关概念,voip 和Sip ,voip的意思是网络电话,会话发起协议(SIP)是建立VOIP连接的IETF标准。SIP是一种应用层协议,用于和一个或多个参与者创建、修改和终止会话。SIP的结构与HTTP(客户-服务器协议)相似。客户机发出请求,并发送给服务器,服务器处理这些请求后给客户机发送一个响应)。

简单点就是voip是网络电话,而sip则是网络电话使用的协议。别的信息就请各位读者自己百度了。至于Android voip程序也就是写一个程序用于实现网络电话功能。

注意:在本篇博客中voip和 sip是一致的,笔者是不分的(原因是在android 2.3以后提供的api中是用sip表示voip相关接口的)

其实关于这个程序还得说明这里的Android 的版本。因为Android版本不同,开发方式也可能不同。voip程序,如果是运行在Android 2.3 以上系统,使用的属于Android 基本变成(简单调用编程api就可以),但是如果用户群体还包括Android 2.3 以前的系统。那就得换方案了,原因如下,因为Android 系统是在2.3以后才支持sip网络电话的,2.3以前就意味着没有对应的编程接口。只能自己实现了。

既然要自己实现,就必须先知道要实现哪些东西(或者说2.3以后和2,3之前到底在sip方面究竟是增加了哪些东西),进过笔者分析2.3和2.2代码的知2.3主要做的是在框架层实现了sip协议还有与sip相关的呼叫管理服务,简单点就是说2.3以后的系统提供了一个支持会话发起协议(SIP)的API,通过它就可以让应用轻松无需管理会话和传输层的沟通就可设置传出和传入的语音通话,或直接音频记录或播放。如果自己实现相关借口还得实现音频编解码。

现在总结一下,在android 2.3 以后的系统上开发voip程序要做的只是调用sip相关api就可以了。但是在Android 2.3 以前的系统上开发voip程序至少得完成如下几件事:

一.实现sip协议栈(在程序中把sip数据包封装好,发到网络上),或者实现别的完成同样功能的协议。

二.实现一个呼叫管理服务功能(例如 来电界面,拨号界面响铃界面等等,试具体功能需求而定)。

三.实现音频编解码(由于Android 的多媒体api中没有提供音频编解码的api,所以得自己实现,但是音频编解码是一个很庞大的事,并且现在有很多开源的音视频编解码库,常见的(笔者接触过的)有BroadVoice (音频编码的),ffmpeg(音视频编解码的),但是这些编解码库大多是以c语言写的。而Android 应用程序开发主要是java。所以在实现编解码音频时就得使用ndk开发(或者jni技术))。相信大家都知道了,开发voip程序在不同版本android上是不同的。而本篇博客主要是在2.3以后版本系统上开发voip
应用至于在2.3以前的开发的情况会在以后的博客中专门说明。

Android2.3 以后开发程序大致步骤如下

1.获取SipManager对象。

2.创建SipProfile对象(但是要先得到SipProfile.Builder 对象 ,并且在获取 Builder 对象时要传入sip账户信息),还得绑定监听器确定是否成功绑定;

3.有了前两个以后就可以拨号了(注意:另一个号也要是sip账号)。

4.使用广播接受器响应Sip呼叫广播(具体是响铃,唤醒屏幕)及设置过滤器。

既然要开发2.3以后的voip程序那就必须知道android系统提供的api相关类有哪些。具体如下:


SipAudioCall


通过SIP处理网络音频电话


SipAudioCall.Listener


关于SIP电话的事件监听器,比如接受到一个电话(on ringing)或者呼出一个电话(on calling)的时候


SipErrorCode


定义在SIP活动中返回的错误代码


SipManager


为SIP任务提供APIs,比如初始化一个SIP连接。提供相关SIP服务的访问。


SipProfile


定义了SIP的相关属性,包含SIP账户、域名和服务器信息


SipProfile.Builder


创建SipProfile的帮助类


SipSession


代表一个SIP会话,跟SIP对话框或者一个没有对话框的独立事务相关联


SipSession.Listener


关于SIP会话的事件监听器,比如注册一个会话(on registering)或者呼出一个电话(on calling)的时候


SipSession.State


定义SIP会话的声明,比如“注册”、“呼出电话”、“打入电话”


SipRegistrationListener


一个关于SIP注册事件监听器的接口

至于 更详细的api相关信息 可以打开这个网页(android sdk api 开发文档英文版) http://docs.huihoo.com/android/2.3/reference/android/net/sip/package-summary.html

熟悉了api以后。就可以开始写程序了。首先呢是创建android 工程。如果不知道具体方法,可以百度。

创建好工程后开始配置买manifest文件

为了使用SIP,需要添加以下权限到你的manifest文件:

§     android.permission.USE_SIP

§     android.permission.INTERNET

为了确保你的应用程序能够安装到支持SIP的设备上,你需要添加以下内容到你应用程序的manifest文件里:

§     <uses-sdkandroid:minSdkVersion="9"/>.这个设置表明你的应用程序需要Android2.3或者更高版本的平台。详情请参考API Levels和<uses-sdk>元素相关的文档。

为了控制你的应用程序被那些不支持SIP的设备过滤掉(比如:在Google Play),你需要添加以下内容到你应用程序的manifest文件里:

§    <uses-featureandroid:name="android.hardware.sip.voip" />.这个设置声明了你的应用程序用到了SIP API。这个声明还应该包含一个android:required属性来表明你是否想让你的应用程序被那些不提供SIP支持的设备过滤掉。其他<uses-feature>声明你也可能需要,具体取决于你的实现,详情请参考<uses-
feature>元素相关的文档。

如果你的应用程序设计用来接受呼叫,那么你还必须在应用程序的manifest文件里定义一个接收器(BroadcastReceiver的子类):

§    <receiverandroid:name=".IncomingCallReceiver"android:label="CallReceiver"/>

综上,manifest文件就出来具体如下

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

package="com.example.android.sip">

<applicationandroid:icon="@drawable/icon" android:label="SipDemo">

<activityandroid:name=".WalkieTalkieActivity"

android:configChanges="orientation|keyboardHidden">

<intent-filter>

<actionandroid:name="android.intent.action.MAIN"/>

<categoryandroid:name="android.intent.category.LAUNCHER"/>

</intent-filter>

</activity>

<activityandroid:name=".SipSettings"android:label="set_preferences"/>

<receiverandroid:name=".IncomingCallReceiver" android:label="CallReceiver"/>

</application>

<uses-sdkandroid:minSdkVersion="9" />

<uses-permission android:name="android.permission.USE_SIP"/>

<uses-permissionandroid:name="android.permission.INTERNET" />

<uses-permissionandroid:name="android.permission.VIBRATE" />

<uses-permissionandroid:name="android.permission.ACCESS_WIFI_STATE" />

<uses-permissionandroid:name="android.permission.WAKE_LOCK" />

<uses-permissionandroid:name="android.permission.RECORD_AUDIO" />

<uses-featureandroid:name="android.hardware.sip.voip"android:required="true" />

<uses-featureandroid:name="android.hardware.wifi"android:required="true" />

<uses-featureandroid:name="android.hardware.microphone"android:required="true" />

</manifest>

配置文件配置好以后 。就可以开始程序编写了。首先得得到

一个SipManager对象,这个对象作用如下;

要想使用SIP API,你的应用程序需要创建一个SipManager对象,这个SipManager对象在你的应用程序里负责以下内容:

1.发起SIP会话

2.发起和接受呼叫

3.在SIP provider里进行注册和注销

4.验证会话的连通性

要提醒的是得到SipManage 对象并不是使用new 而是使用英文文档中的如下函数


static                          SipManager


newInstance(Context 
context)

Creates a manager instance.

使用以上函数就可得到SipManage对象。然后还得在Sip服务器上注册(一个典型的Android SIP应用中包含一个或多个用户,他们中的每个人都有一个SIP账户),

在Android SIP应用中,每一个SIP账户代表一个SipProfile对象。

一个SipProfile对象定义了一个SIP的概要文件,包括SIP账户、域名和服务器信息。跟正在这个设备上运行应用的SIP账户相关联的概要文件被称之为本地配置文件。与会话相连接的概要文件被称之为对应配置文件。当你的SIP应用通过本地SipProfile登录到SIP服务器的时候,这就有效的注册当前设备为基站来发送SIP呼叫到你想呼叫的SIP地址。所以呢,接下来要做的就是创建一个SipProfile,以及如何把刚创建的SipProfile注册到SIP服务器上,并且跟踪注册事件。要的到SipProfile对象,使用的是SipProfile.Builder这个类的函数,也就是说得先创建Builder
的对象,该类的构造函数如下:


SipProfile.Builder(SipProfile 
profile)

Creates a builder based on  the given profile.(拷贝构造)


SipProfile.Builder(String   
uriString)

Constructor.

SipProfile.Builder(String
username, StringserverDomain)

Constructor.(通过用户名和服务器地址构造)

三个都可以使用,但是常用的是第三个,(一般情况sip账户还有密码,这时候还得使用


SipProfile.Builder


setPassword(String 
password)

Sets the password of the SIP  account

这函数设置密码,其实builder 还有一些函数(包括设置端口号等信息系),根据具体情况来使用。)。

得到Builder 对象后使用其


SipProfile


build()

Builds and returns the SIP  profile object.

就可以得到SipProfile对象。接着就得开始处理被呼叫时的反应了。用于呼出电话和/或接收通用的SIP电话。呼叫器可以通过mSipManager.makeAudioCall来呼出后续电话。这段摘录同样设置了一个android.SipDemo.INCOMING_CALL行动,这个行动会被一个intent过滤器来使用,当前设备接收到一个呼叫(见Setting up an intent filter to receive calls)。

Intent intent = newIntent();

intent.setAction("android.SipDemo.INCOMING_CALL");

PendingIntent pendingIntent=PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);

mSipManager.open(mSipProfile,pendingIntent,null);

还得绑定监听器用于检测sip用户的注册结果及错误信息

mSipManager.setRegistrationListener(mSipProfile.getUriString(),new SipRegistrationListener() {

public void onRegistering(StringlocalProfileUri) {

updateStatus("Registering with SIPServer...");

}

public void onRegistrationDone(StringlocalProfileUri, long expiryTime) {

updateStatus("Ready");

}

public void onRegistrationFailed(StringlocalProfileUri, int errorCode,

String errorMessage) {

updateStatus("Registrationfailed.  Please checksettings.");

}

最后还得释放掉(关闭)profile及在服务器上注销该账户 。

mSipManager.close(mSipProfile.getUriString());

就可以了。

到这里的话 程序里就会存在一个正常的记录用户信息的Profile对象(若这个对象绑定的监听器提示注册失败,就说明你的信息错误(可能是用户名,密码,服务器地址或者端口号等等,这时只能在核对信息了)及一个SipManager对象。)这时就可以拨打开始语音电话部分了。

要想拨打一个语音电话,要建立一个SipAudioCall.Listener监听器。大部分客户与SIP堆栈的交互都是通过监听器来发生的。在这一小段你将会看到SipAudioCall.Listener监听器是如何在呼叫制定之后建立事务的:

SipAudioCall.Listener listener= newSipAudioCall.Listener() {

@Override

publicvoidonCallEstablished(SipAudioCall call) {

call.startAudio();

call.setSpeakerMode(true);

call.toggleMute();

}

@Override

publicvoidonCallEnded(SipAudioCall call) {

// Dosomething.

}

};

一旦你创建了这个SipAudioCall.Listener监听器,你就可以拨打电话了,SipManager对象里的makeAudioCall方法接受以下参数:

一个本地SIP配置文件(呼叫方)

一个相对应的SIP配置文件(被呼叫方)

一个用来监听从SipAudioCall发出的呼叫事件的SipAudioCall.Listener,这个参数可以为null,但是如上所说,一旦呼叫电话制定,这个监听器将被用来创建事务

超时的值,以秒为单位

例如:

call=mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress,listener,30);

这样拨号过程中的信息就可以在listener中得到了。

现在拨号已没问题了。

接下来就要处理被呼叫的情况了。首先得知道android系统在有呼叫过程发生时是通过广播的形式发送有来电的消息,所以为了接收呼叫,你的SIP应用必须实现BroadcastReceiver的子类。当Android系统接收到一个呼叫的时候,他会处理这个SIP呼叫,然后广播一个来电intent(这个intent由系统来定义),

如下就是代码:

public class IncomingCallReceiverextends BroadcastReceiver {

/**

* Processes the incoming call, answers it,and hands it over to the

* WalkieTalkieActivity.

* @param context The context under whichthe receiver is running.

* @param intent The intent being received.

*/

@Override

public void onReceive(Context context,Intent intent) {

SipAudioCall incomingCall = null;

try {

SipAudioCall.Listener listener =new SipAudioCall.Listener() {

@Override

public voidonRinging(SipAudioCall call, SipProfile caller) {

try {

call.answerCall(30);

} catch (Exception e) {

e.printStackTrace();

}

}

};

WalkieTalkieActivity wtActivity =(WalkieTalkieActivity) context;

incomingCall =wtActivity.manager.takeAudioCall(intent, listener);

incomingCall.answerCall(30);

incomingCall.startAudio();

incomingCall.setSpeakerMode(true);

if(incomingCall.isMuted()) {

incomingCall.toggleMute();

}

wtActivity.call = incomingCall;

wtActivity.updateStatus(incomingCall);

} catch (Exception e) {

if (incomingCall != null) {

incomingCall.close();

}

}

}

}

这样呢当这个广播接收器收到广播时,就会唤醒手机以及响铃。但是只有这个还不够,还要为广播监听器进行广播过滤,(因为android 系统不仅发送来电的广播,还有很多别的广播(例如启动完成以后,电量变化等等 ))。

设置过滤器代码如下:

Intent intent = newIntent();

intent.setAction("android.SipDemo.INCOMING_CALL");  //sip电话呼叫

PendingIntent pendingIntent=PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);

mSipManager.open(mSipProfile,pendingIntent,null);  //打开SipManager。

这时候 就可以接受呼叫了。

这样一个Android voip程序就好了。

特别说明:本篇博客来源于android sdk 19 sample代码中的SipDemo的例子,这是google官方提供的sdk使用例子。

笔者也将那个例子上传到csdn   http://download.csdn.net/detail/huang_rong12/9504286      这是免积分的,这个工程导入eclipse 后就可以运行的。

还有如果各位想转载的话请注明原帖地址(让别人有问题时可以找到这里,当然若您有信心解决读者的问题,不注明也可以的)。

有什么问题的话可以在评论处留言。我看见后会回复的。

时间: 2024-10-11 11:09:54

Android 开发 voip/sip 程序的相关文章

Android开发之应用程序更新实现

最近给项目app做升级,对Android应用程序更新稍有研究,分享一下我的心得. 既然是更新,那么一定是要联网和下载的,所以联网和存储访问权限时一定要有的: <!-- 权限申请 --> <uses-permission android:name="android.permission.INTERNET" /> <!-- 联网权限 --> <uses-permission android:name="android.permission

Android 开发的QQ程序源码

Android 开发的QQ程序源码 网上下载的一款Android 开发的QQ程序源码,其中有大量的注释.项目中有错误不能直接运行,有兴趣的朋友可以下载看下. 下载地址:http://www.devstore.cn/code/info/841.html  运行截图:

Android开发eclipse运行程序时报timeout的解决方法

eclipse开发Android程序时,忽然莫名其妙报这个错,之前还好好的.忽然就不行了. Failed to install xxx.apk on device~~~: timeout 尝试过手机里删除应用程序.手机重启.重启adb.重启eclipse.重启电脑后,还是不行. 尝试了半天,找到了方案: eclipse-->window-->Preferences-->Android-->DDMS-->ADB connection time out(ms) 里面的值默认为50

Android开发之在程序右上角添加菜单选项

在res-->menu-->main.xml中定义菜单的选项 <menu xmlns:android="http://schemas.android.com/apk/res/android" >    <item        android:id="@+id/item1"        android:title="主页">    </item>    <item        androi

android开发的应用程序,用模拟器可以访问,但是安装到手机上却不行

============问题描述============ 开发一个与数据库返回数据的程序,服务端是用servlet写的,用模拟器测试时,是能够访问的,且能返回数据,但是把程序安装到手机上,却不能访问服务端了,请问是为什么啊 ============解决方案1============ 肯定的啊,你手机的ip和你模拟器的不一样!你模拟器用的是和电脑默认的一个地址,你修改下手机的ip,改成你访问路径的那个地址试试. ============解决方案2============ 服务端是你本机吗? 如果是

(三十七)Android开发中修改程序字体

1.在Android XML文件中设置系统默认的字体 可以在XML文件中采用android:typeface设置字体,例如android:typeface=”monospace”.在这里例子中我们在Activity中对android:text=”Hello, World! 您好”分别进行了四种显示方式,依次为“Sans”,“serif”,“monospace”和系统缺省方式(经试验缺省采用采用sans).英文字体有差异,貌似中文字体没有差异.XML文件如下: <?xml version=“1.0

iOS开发之使用pjsip开发VoIP应用程序

转自:http://www.wuleilei.com/blog/327 最近项目中要用到VoIP,VoIP全称Voice over Internet Protocol,即网络电话,生活中经常用到,例如Skype. 能用到iPhone上面的VoIP库不多,最开始准备使用Lipphone,但其编译实在太慢,编译了N次也没有成功,最后放弃啦.后来尝试使用pjsip,居然成功了,简单的记录一下过程,其实是照着官网操作的:) 一.环境需求: iPhone应用推荐使用SDK 4.x,当然3.x也支持:iPa

写给 Android 开发的小程序布局指南,Flex 布局!

一.序 Hi,大家好,我是承香墨影! 最近在做小程序,验证一些方向,开发效率确实很快,就是各种微信的审核有点费劲,但是总归是有办法解决的. 想要开发一款小程序,其实和我们正常写一款 App 类似,你需要有精美的前端布局,并且同时还需要处理和前端 UI 组件的交互以及它们背后的逻辑. 最近会分享一些关于小程序的内容(不保证,想到哪里写到哪里),今天先说说接触小程序第一步:布局. 如果有前端经验的话,小程序是非常容易上手的,而对于新手,第一步当然是阅读小程序的官方文档,不过之后你马上就要面临布局的问

android开发中的5种存储数据方式

数据存储在开发中是使用最频繁的,根据不同的情况选择不同的存储数据方式对于提高开发效率很有帮助.下面笔者在主要介绍Android平台中实现数据存储的5种方式. 1.使用SharedPreferences存储数据 SharedPreferences是Android平台上一个轻量级的存储类,主要是保存一些常用的配置比如窗口状态,一般在Activity中 重载窗口状态onSaveInstance State保存一般使用SharedPreferences完成,它提供了Android平台常规的Long长 整