您的位置:首页 > 移动开发 > Android开发

Pro Android学习笔记(一二五):Telephony API(7):SIP Phone(下)

2014-09-16 21:47 375 查看
文章转载只能用于非商业性质,且不能带有虚拟货币、积分、注册等附加条件。转载须注明出处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 = "78000009@192.168.1.10: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开发相关文章
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐