0
点赞
收藏
分享

微信扫一扫

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

发起呼叫

发起呼叫,要确保客户端正常发送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;        
 }

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

我要补充的是,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(); 
         }          
     } 

 }

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

对于被叫,andriod.net.sip不支持INVITE不带sdp方式,会报“seesion description missing in incoming call intent”的错误。

总的来讲android.net.sip高度封装,完成要给sip phone很容易,但是很多无法调整,在实际应用中会受到限制,基本上还是自己处理的为好。


举报

相关推荐

0 条评论