文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处http://blog.csdn.net/flowingflying以及作者@恺风Wei。
发起呼叫,要确保客户端正常发送RTP包,需要增加两个新的权限:
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
发起呼叫的代码片段如下:
public SipAudioCall myCall = null;
public void onOutgoingCall(View v){
if(myCall != null){
myCall.close();
}
try{ //设置状态监听器
SipAudioCall.Listener listener = new SipAudioCall.Listener(){
@Override //通话建立(对方接通),即收到SIP INVITE的200OK消息,并回复ACK时触发
public void onCallEstablished(SipAudioCall call) {
call.startAudio(); //在sip信令接通后,进行语音的处理
call.setSpeakerMode(true);
debug("onCallEstablished");
}
@Override //通话结束,指捕获通话建立后对方挂机,如果本方主动挂机,是不会触发此状态。如果对方拒听,可以在onError(SipAudaioCall call, int errorCode, String errorMessage)中获取,通过errorCode:-7和errorMessage:Temporarily Unavailable (480)。
public void onCallEnded(SipAudioCall call) {
debug("onCallEnded");
}
};
String called = "[email protected]:54712"; //我们用Xlite作为SIP的另一个UA,无需通过软交换,直接填入该终端的地址。
myCall = sipManager.makeAudioCall(mySipProfile.getUriString(), called, listener, 30);
}catch(Exception e){
debug("onOutgoingCall ERROR: "+ e.toString());
e.printStackTrace();
}
}
android.net.sip还提供了myCall.toggleMute()实现静音和非静音的切换,通过isMute()来检查当前是否是静音。静音时无RTP发送。SipDemo就是通过toogleMute()实现对讲的功能。
主动挂机的代码片段如下,包括通话后挂机(发送BYTE),以及建立呼叫的过程中终止(发送CANCEL)。
public void endCall(){
if(myCall == null)
return;
try{
myCall.endCall(); //停止通话
}catch(Exception e){
debug("onEndCall ERROR: "+ e.toString());
e.printStackTrace();
}
myCall.close(); //关闭object,不能再用,释放object
myCall = null;
}
我要补充的是,SDP协商为PCMU,抓包看到双方都有RTP了,但是有问题,不能听到对方说啥,XLite听到的是噪音,因此应有什么东西欠缺,具体如何处理Audio还是很有问题,这可能也与测试机型有关,所以这个sip包,我觉得不实用。
我们仍用XLite来模拟,将domain设置为我们的小例子的sip地址(要带端口号),不采用register方式,这样在没有软交换的情况下,XLite的拨出电话都会打到我们的小例子。
在上一次笔记中,自动register的方式如下,我们查看了sipManager的说明,没有发现其他方法可以携带PendingIntent,因此作为被叫,必须采用自动register的方式,在收到呼叫时,触发一个广播intent。
Intent i = new Intent();
i.setAction("cn.wei.flowingflying.mysipphone.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
sipManager.open(mySipProfile, pi, null);
我们需要在AndroidManifest.xml中声明接收器,也可以在代码中进行注册。根据小例子的特点,在代码中进行注册更为合适。
IncomingCallReceiver receiver = new IncomingCallReceiver(this);
…… 进行注册,例如在onCreate()中……
IntentFilter filter = new IntentFilter();
filter.addAction("cn.wei.flowingflying.mysipphone.INCOMING_CALL");
this.registerReceiver(receiver, filter);
……进行注销,例如在onDestroy()中….
this.unregisterReceiver(receiver);
接收器代码如下:
public class IncomingCallReceiver extends BroadcastReceiver{
private MainActivity activity = null; //主Activity的对象
private static boolean isEnd = false;
public IncomingCallReceiver(MainActivity activity){
this.activity = activity;
}
@Override
public void onReceive(Context context, Intent intent) {
activity.debug("--------receiver--------");
try{
//设置监听器,准备进行状态检测,和呼出一样,能触发的对方的状态,而非本方
SipAudioCall.Listener listener = new SipAudioCall.Listener(){
@Override //实际不会触发到onRinging,这是对方Ringing(180)而非本方
public void onRinging(SipAudioCall call, SipProfile caller) {
activity.debug("onRing..............");
}
@Override //呼叫建立可触发,是在answerCall()(发送200OK)后收到ACK时触发
public void onCallEstablished(SipAudioCall call) {
activity.debug("onCallEstablished..............");
}
@Override //对方挂机时触发,包括接通和未接通的挂机
public void onCallEnded(SipAudioCall call) {
activity.debug("onCallEnded..............");
isEnd = true;
call.close();
}
@Override
public void onError(SipAudioCall call, int errorCode, String errorMessage) {
activity.debug("onError : " + errorMessage);
}
};
// 通过takeAudioCall()获得呼叫的session,并设置监测器
SipAudioCall incomingCall = activity.sipManager.takeAudioCall(intent, listener);
Thread.sleep(2000); //模拟2秒后接通
if(isEnd){ //对方可能已经在未接通前主动挂架,故要进行检查
incomingCall.answerCall(30); //接通,发送200OK,并有30秒时间等待ACK的应当
incomingCall.startAudio();
incomingCall.setSpeakerMode(true);
activity.myCall = incomingCall; //使得activity的UI的挂机可以操作
}
}catch(Exception e){
activity.debug("INCOMING CALL ERROR : " + e.toString());
e.printStackTrace();
}
}
}
对于被叫,andriod.net.sip不支持INVITE不带sdp方式,会报“seesion description missing in incoming call intent”的错误。
总的来讲android.net.sip高度封装,完成要给sip phone很容易,但是很多无法调整,在实际应用中会受到限制,基本上还是自己处理的为好。
相关链接:我的Android开发相关文章