android sip协议通话代码实现
- 简介
- android里面的VOIP网络通话基于sip(Session initiation protocol)协议;android已经集成了sip协议栈,并提供了相应的API给应用开放使用,开发者不需要了解具体的协议内容
-
基于sip的网络通话基本过程
- 建立SIP服务器,关于如何建立SIP服务器,请参考这篇文章
- 需要所有参与通话的客户端注册用户到SIP服务器
- 一个客户端发起SIP通话到另一个客户端,这个消息首先发到SIP服务器,sip服务器收到消息后转发到目的客户端
- 目的客户端接收电话
-
关于SIP网络通话的主要类和描述如下表所示:
<table>
<tbody><tr>
<th>类/接口</th>
<th>描述</th></tr> <tr> <th>SipAudioCall</th> <th>通过SIP处理网络音频电话</th> </tr> <tr> <th>SipAudioCall.Listener</th> <th> 关于SIP电话的事件监听器,比如收到一个电话(on ringing)或者呼出一个电话(on calling)</th> </tr> <tr> <th>SipErrorCode</th> <th>定义在SIP活动中的错误代码</th> </tr> <tr> <th>SipManager</th> <th> 为SIP任务提供APIs,比如初始化一个SIP连接,提供相关SIP服务的访问。</th> </tr> <tr> <th>SipProfile</th> <th> 定义了SIP的相关属性,包含SIP账户、域名和服务器信息</th> </tr> <tr> <th>SipProfile.Builder</th> <th> 创建SipProfile的帮助类</th> </tr> <tr> <th>SipSession</th> <th>代表一个SIP会话,跟SIP对话框或者一个没有对话框的独立事务相关联</th> </tr> <tr> <th> SipSession.Listener</th> <th> 关于SIP会话的事件监听器,比如注册一个会话(on registering)或者呼出一个电话(on calling)的时候</th> </tr>
<tr>
<th> SipSession.State</th>
<th>定义SIP会话的声明,比如“注册”、“呼出电话”、“打入电话”</th>
</tr>
<tr>
<th> SipRegistrationListener</th>
<th> 一个关于SIP注册事件监 听器的接口</th></tr></tbody></table>
-
在应用的AndroidManifest.xml中需要声明下面权限和特征
<uses-permission android:name="android.permission.USE_SIP" /> <uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.VIBRATE" /> <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" /> <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" /> <uses-feature android:name="android.hardware.sip.voip" android:required="true" /> <uses-feature android:name="android.hardware.wifi" android:required="true" /> <uses-feature android:name="android.hardware.microphone" android:required="true" />
-
构造一个SipManager实例.
SipManager manager = SipManager.newInstance(this); //必须调用此方法创建,这是因为该方法会判断设备是否支持sip协议PackageManager.FEATURE_SIP 如果有的android设备不支持,可以添加android.software.sip.voip.xml和android.software.sip.xml到/system/etc/permissions/下
- 下面代码是注册一个账户到SIP服务器
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
//uesrname表示注册用户名,domain表示域,实际就是sip服务器ip
builder.setPassword(password); //注册用户密码
SipProfile me = builder.build(); //构造一个SipProfile对象,也就是相当于一个账户信息
Intent i = new Intent();
i.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
//构造一个PendingIntent对象,这样当sip Service收到一个通话请求时,
//例如收到一个来电时,SipService会调用PendingIntent的send方法发送相应广播消息给调用者,也就是当前的SipProfile对象.
manager.open(me, pi, null); //此处就是用于注册一个账户到sip服务器
//注册一个监听器,用于获取注册账户时的通知状态,当然也可以不注册.
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) { //正在注册
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {//注册成功
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
}
});
-
开始拨号,从一个设备拨打电话到另一个设备,前提是两个设备都已注册,且知道目的设备的sip账户信息.
try { SipAudioCall.Listener listener = new SipAudioCall.Listener() { // Much of the client's interaction with the SIP Stack will // happen via listeners. Even making an outgoing call, don't // forget to set up a listener to set things up once the call is established. @Override public void onCallEstablished(SipAudioCall call) { //当网络通话建立了之后,会收到此通知 call.startAudio(); //启动音频 call.setSpeakerMode(true); //设置为扬声器模式,也就是开启回声抑制 call.toggleMute(); //切换静音,注意默认为非静音,调用此方法后变为静音了 } @Override public void onCallEnded(SipAudioCall call) { } }; //注意此处的makeAudioCall方法就是打网络电话的,localProfile就是本地设备的SipProfile对象, //PeerProfile就是目标设备的SipProfile对象,listener是监听器 SipAudioCall call = manager.makeAudioCall(localProfile.getUriString(), PeerProfile, listener, 30);}catch (Exception e) { }
-
注意,此处的SipProfile的内容格式,例如,LocalProfile的url格式为"sip:abcde123@10.0.149.240",PeerProfile的url格式为"sip:abcde234@10.0.149.240",url内容也就是sip账户,
其中:(1) sip: 表示采用sip协议 (2) abcde123和abcde234是用户名, 也称为帐号. 用字母和数字均可。 (3) 10.0.149.240是sip账户所属的服务器地址(当然也可以用域名来表示) (4) SIP协议默认端口为5060, 默认采用UDP传输,如果需要指定端口为5678,可以修改为sip:abcde123@10.0.149.240:5678,
-
从localProfile和peerProfile指定的内容可以看出,账户名作为唯一标识,由sip服务器来解析账户名,从而找到对应的目的主机.
- 目的端接收通话
根据前面的分析,一个设备拨打电话到目的设备时,在目的设备的sip服务(SipService)会发送一个广播消息给当前的目的设备。因此必须提前注册一个广播接收器来接收此消息,这样才知道有来电通知,可以在AndroidManifest.xml静态注册,也可以在应用程序中动态注册,因此下面代码必须放在广播接收器的onReceive()方法中:
-
案例:
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() { @Override public void onRinging(SipAudioCall call, SipProfile caller) { try { call.answerCall(30); } catch (Exception e) { e.printStackTrace(); } } }; //takeAudioCall就表示需要为接听电话创建一个SipAudioCall对象. SipAudioCall incomingCall = manager.takeAudioCall(intent, listener); incomingCall.answerCall(30); //接听电话 incomingCall.startAudio(); //启动音频 incomingCall.setSpeakerMode(true);
-
注意点:
1.所有参与网络通话的设备和sip服务器的网络必须是连接的,网络类型可以是以太网,wifi,mobile等都可以. 如果通话过程有问题,可以检测设备网络收发包是否正常. 2.对应的设备必须支持sip,voip功能才行.
-