zoukankan      html  css  js  c++  java
  • Android Sip学习(三)Android Voip实现

    Android Sip学习(三)Android Voip实现

     

    Android Sip学习(准备知识)SIP 协议完整的呼叫流程

    Android Sip学习(一)Android 2.3 APIs SIP-based VoIP

    Android Sip学习(二)Android VoIP系统实现原理

    Android Sip学习(三)Android Voip实现

    Android Sip学习(四)Android自带SipDemo详解

    回顾下:

    一、基本概念

    1、VOIP基于SIP协议,SDK2.3包含一个SIP协议栈和框架API

    2、VOIP位于android.net.sip包中,最重要的为SipManager类,可开发基于SIP的VOIP应用。使用时要包含android.permission.INTERNET和android.permission.USE_SIP权限

    3、如果在market中显示仅支持VOIP API型号的手机的话,发布时需要在androidManifest.xml中加入<uses_feature android:name = "android.software.sip" android:required = "true">和<uses_feature android:name = "android.software.sip.voip">

    4、要支持SIP API

         (1)仅Android2.3或更高版本平台支持

         (2)不是所有设备都提供SIP支持,确保你的APP只安装在支持SIP的装置上

    5、根据GOOGLE官方DEMO项目来扩展的概念

    二、类及方法描述

    1、一个基本的VOIP项目至少需要三个类SIPSettings(对SIP的基本设置身份验证)、WalkieTalkieActivity(登 录到SIP设备供应商,注册device去处理来电,拨打电话,在通话过程中用户界面管理)、IncomingCallReceiver(监听传入的 SIP电话,然后传递这些SIP电话给WalkieTalkieActivity控制)

    2、

     WalkieTalkieActivity

    A、SipManager.newInstance()-->此方法中首先判断context是否支持SIP API,若支持则new SipManager。SipManager构造函数中,实例化了一个ISIPService(运用的公式:

    Java Code复制内容到剪贴板
    1. IBinder b =ServiceManager.getService(Context.SIP_SERVICE);  //获取系统相应的服务  
    2. ISipService service = ISipService.Stub.asInterface(bIBinder);)  

    上面这两句代码其实是使用了AIDL,就以SipService为例,步骤如下
    Service端
    1、编写aidl文件:ISipService.aidl,并定义使用的接口(就等同于interface一样)
    2、使用makefile生成与之同名的JAVA文件,SipService.java,此类继承extends ISipService.Stub并实现接口定义的方法或者在SipService extends Service,并代码中加入
    ISipService.stub sipImpl = new ISipService.stub(){
    //实现其接口方法,在SipService.java中是实现了一个名为start()的方法,里面有句是 ServiceManager.addService("sip",newSipService(context));表示SipService已经交给 ServiceManager统一管理了
    }

    Client端
    一(以SIPService为例)
    1、而在需要用到SipService时,也就是我们构造SipManager的时候,就通过ServiceManager.getService(Context.SIP_SERVICE)获得SIP的服务(类型为IBinder)
    2、并调用 ISipService.Stub.asInterface(IBinder);去获取一个SipService实例(前提是该Service一定是通过 ServiceManager.addService的方式添加进去管理的,这样才能找到此Service)


    二(以普通Activity为例)
    1、利用Intent intent = new Intent(Activity.this,SipService.class);-->bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);来绑定SERVICE,在serviceConnection的 onServiceConnected方法中,使用IService.stub.asIntentface(IBinder);来获取实例


    B、SipManager创建好后,先从SharedPreference中获取username,domain及pwd,如果第一次进来没有设置这些的 话则需要先创建账户,这里用EditTextPreference来保存用户信息,好处是当填写信息并返回后,EditTextPreference会自 动将值放入SharedPreference中。我们假设username="woody";domain="192.168.12.30"; pwd="910913"

    C、这时,我们的SipManager以及用户信息已经设定好了,接下来使用了这句SipProfile.Builder builder = new SipProfile.Builder(username, domain);我们去看看SipProfile.Builder中做了些什么:
     

    Java Code复制内容到剪贴板
    1. SipURI mUri =mAddressFactory.createSipURI(username,serverDomain);  
    2. SipProfile mProfile.mDomain=serverDomain; //设置domain  
    3. (在mAddressFactory.createSipURl方法中,我选取了一些核心代码)  
    4. StringBuffer uriString=new StringBuffer("sip:");   
    5. uriString.append(user);   
    6. uriString.append("@");   
    7. //if host is an IPv6 string we should enclose it in sq brackets  
    8. if(host.indexOf(':') !=host.lastIndexOf(':')&&host.trim().charAt(0) !='[')   
    9.    host='['+host+']';   
    10. uriString.append(host);  
    11. StringMsgParser smp=new StringMsgParser();   
    12.   
    13. SipUrl sipUri=smp.parseSIPUrl(uriString.toString());   
    14. return sipUri;  

    从以上代码可以看出其实就是在Format SipURL罢了,里面多加了个if host为IPV6的判断(IPv4为为32位,十进制;IPv6为128位,16进制)。urlString最后 为"sip:woody@192.168.12.30",smp.parseSIPUrl()方法中,有关于是如何parse的就不做阐述了,总之最后返 回了一个SipUri

    D、接下来就是SipProfile sipProfile = SipProfile.Builder.build(); //返回一个SipProfile object
    在SipProfile.Builder.build()中,设置了sipProfile的pwd值,删除了之前SipUrl对象里的 password(mUri.setUserPassword(null);)、将sipProfile的address属性设置为 AddressImpl类型的对象值、调用AddressFactory.createURI返回一个SipUri,并 sipProfile.mProxyAddress=sipUri.getHost();


    E、创建PendingIntent对象:(Intent与PendingIntent区别在于Intent是及时启动,而PendingIntent是不立刻反应,在特定的情况或通知下才启动,适用于AlertClock等)
     

    Java Code复制内容到剪贴板
    1. Intent i = new Intent();  
    2. i.setAction("android.SipDemo.INCOMING_CALL");  
    3. PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);  

    F、
    SipManager.open(sipProfile,PendingIntent,null); //(实际是SIPService在做操作)设置localSIPProfile的callingID-->建立SIP连接(算是注册至SIP Server)-->打开receiveCall
    其中建立SIP连接,最后能追溯到是在SipSessionGroup.java的reset()方法中通过是注册服务器实现的,如下图
    QQ截图20130808164903.jpg

    注册服务器的步骤为:
    (1)设置服务器的属性,例如服务器的地址(IP_ADDRESS_PROP)、栈名(javax.sip.STACK_NAME)、发出去的路径 (localProfile中的javax.sip.OUTBOUND_PROXY)、线程池的大小 (gov.nist.javax.sip.THREAD_POOL_SIZE)等,并且将这些属性加载到服务器中.
    (2)通过SipFactory的静态方法取得一个实例,然后通过SipFactory实例sipfactory
    (3)创建一个SipStack实例sipstack(这一步获得IP_ADDRESS_PROP,String address = Properties.getProperty("javax.sip.IP_ADDRESS");)
    (4)用sipstack创建一个SipProvider实例sipProvider
    (5)注册SipListener

    Android Sip学习(三)Android Voip实现

    时间:2013-08-08 17:03:03  来源:束洋洋博客  作者:束洋洋

    Android Sip学习(准备知识)SIP 协议完整的呼叫流程

    Android Sip学习(一)Android 2.3 APIs SIP-based VoIP

    Android Sip学习(二)Android VoIP系统实现原理

    Android Sip学习(三)Android Voip实现

    Android Sip学习(四)Android自带SipDemo详解

    回顾下:

    一、基本概念

    1、VOIP基于SIP协议,SDK2.3包含一个SIP协议栈和框架API

    2、VOIP位于android.net.sip包中,最重要的为SipManager类,可开发基于SIP的VOIP应用。使用时要包含android.permission.INTERNET和android.permission.USE_SIP权限

    3、如果在market中显示仅支持VOIP API型号的手机的话,发布时需要在androidManifest.xml中加入<uses_feature android:name = "android.software.sip" android:required = "true">和<uses_feature android:name = "android.software.sip.voip">

    4、要支持SIP API

         (1)仅Android2.3或更高版本平台支持

         (2)不是所有设备都提供SIP支持,确保你的APP只安装在支持SIP的装置上

    5、根据GOOGLE官方DEMO项目来扩展的概念

    二、类及方法描述

    1、一个基本的VOIP项目至少需要三个类SIPSettings(对SIP的基本设置身份验证)、WalkieTalkieActivity(登 录到SIP设备供应商,注册device去处理来电,拨打电话,在通话过程中用户界面管理)、IncomingCallReceiver(监听传入的 SIP电话,然后传递这些SIP电话给WalkieTalkieActivity控制)

    2、

     WalkieTalkieActivity

    A、SipManager.newInstance()-->此方法中首先判断context是否支持SIP API,若支持则new SipManager。SipManager构造函数中,实例化了一个ISIPService(运用的公式:

    Java Code复制内容到剪贴板
    1. IBinder b =ServiceManager.getService(Context.SIP_SERVICE);  //获取系统相应的服务  
    2. ISipService service = ISipService.Stub.asInterface(bIBinder);)  

    上面这两句代码其实是使用了AIDL,就以SipService为例,步骤如下
    Service端
    1、编写aidl文件:ISipService.aidl,并定义使用的接口(就等同于interface一样)
    2、使用makefile生成与之同名的JAVA文件,SipService.java,此类继承extends ISipService.Stub并实现接口定义的方法或者在SipService extends Service,并代码中加入
    ISipService.stub sipImpl = new ISipService.stub(){
    //实现其接口方法,在SipService.java中是实现了一个名为start()的方法,里面有句是 ServiceManager.addService("sip",newSipService(context));表示SipService已经交给 ServiceManager统一管理了
    }

    Client端
    一(以SIPService为例)
    1、而在需要用到SipService时,也就是我们构造SipManager的时候,就通过ServiceManager.getService(Context.SIP_SERVICE)获得SIP的服务(类型为IBinder)
    2、并调用 ISipService.Stub.asInterface(IBinder);去获取一个SipService实例(前提是该Service一定是通过 ServiceManager.addService的方式添加进去管理的,这样才能找到此Service)


    二(以普通Activity为例)
    1、利用Intent intent = new Intent(Activity.this,SipService.class);-->bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);来绑定SERVICE,在serviceConnection的 onServiceConnected方法中,使用IService.stub.asIntentface(IBinder);来获取实例


    B、SipManager创建好后,先从SharedPreference中获取username,domain及pwd,如果第一次进来没有设置这些的 话则需要先创建账户,这里用EditTextPreference来保存用户信息,好处是当填写信息并返回后,EditTextPreference会自 动将值放入SharedPreference中。我们假设username="woody";domain="192.168.12.30"; pwd="910913"

    C、这时,我们的SipManager以及用户信息已经设定好了,接下来使用了这句SipProfile.Builder builder = new SipProfile.Builder(username, domain);我们去看看SipProfile.Builder中做了些什么:
     

    Java Code复制内容到剪贴板
    1. SipURI mUri =mAddressFactory.createSipURI(username,serverDomain);  
    2. SipProfile mProfile.mDomain=serverDomain; //设置domain  
    3. (在mAddressFactory.createSipURl方法中,我选取了一些核心代码)  
    4. StringBuffer uriString=new StringBuffer("sip:");   
    5. uriString.append(user);   
    6. uriString.append("@");   
    7. //if host is an IPv6 string we should enclose it in sq brackets  
    8. if(host.indexOf(':') !=host.lastIndexOf(':')&&host.trim().charAt(0) !='[')   
    9.    host='['+host+']';   
    10. uriString.append(host);  
    11. StringMsgParser smp=new StringMsgParser();   
    12.   
    13. SipUrl sipUri=smp.parseSIPUrl(uriString.toString());   
    14. return sipUri;  

    从以上代码可以看出其实就是在Format SipURL罢了,里面多加了个if host为IPV6的判断(IPv4为为32位,十进制;IPv6为128位,16进制)。urlString最后 为"sip:woody@192.168.12.30",smp.parseSIPUrl()方法中,有关于是如何parse的就不做阐述了,总之最后返 回了一个SipUri

    D、接下来就是SipProfile sipProfile = SipProfile.Builder.build(); //返回一个SipProfile object
    在SipProfile.Builder.build()中,设置了sipProfile的pwd值,删除了之前SipUrl对象里的 password(mUri.setUserPassword(null);)、将sipProfile的address属性设置为 AddressImpl类型的对象值、调用AddressFactory.createURI返回一个SipUri,并 sipProfile.mProxyAddress=sipUri.getHost();


    E、创建PendingIntent对象:(Intent与PendingIntent区别在于Intent是及时启动,而PendingIntent是不立刻反应,在特定的情况或通知下才启动,适用于AlertClock等)
     

    Java Code复制内容到剪贴板
    1. Intent i = new Intent();  
    2. i.setAction("android.SipDemo.INCOMING_CALL");  
    3. PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);  

    F、
    SipManager.open(sipProfile,PendingIntent,null); //(实际是SIPService在做操作)设置localSIPProfile的callingID-->建立SIP连接(算是注册至SIP Server)-->打开receiveCall
    其中建立SIP连接,最后能追溯到是在SipSessionGroup.java的reset()方法中通过是注册服务器实现的,如下图
    QQ截图20130808164903.jpg

    注册服务器的步骤为:
    (1)设置服务器的属性,例如服务器的地址(IP_ADDRESS_PROP)、栈名(javax.sip.STACK_NAME)、发出去的路径 (localProfile中的javax.sip.OUTBOUND_PROXY)、线程池的大小 (gov.nist.javax.sip.THREAD_POOL_SIZE)等,并且将这些属性加载到服务器中.
    (2)通过SipFactory的静态方法取得一个实例,然后通过SipFactory实例sipfactory
    (3)创建一个SipStack实例sipstack(这一步获得IP_ADDRESS_PROP,String address = Properties.getProperty("javax.sip.IP_ADDRESS");)
    (4)用sipstack创建一个SipProvider实例sipProvider
    (5)注册SipListener

    G、A~F步骤都是在做准备工作,大致的步骤如下:new SIPService-->new SIPManager-->设定用户信息-->new SIPURI-->new SIPProfile-->new PendingIntent-->set sipProfile callingID-->(if profile.getAutoRegistation)open toReceiveCalls-->register SipService
    现在是call someone~呼叫的工作是SipAudioCall类来完成(可用sipManager.makeAudioCall或takeAudioCall来 实例化,SipAudioCall.startAudio时需要 RECORD_AUDIO, ACCESS_WIFI_STATE, and WAKE_LOCK permissions,setSpeakerMode() 时需要MODIFY_AUDIO_SETTINGS permission)
    【1】当需要呼叫时,使用sipManager.makeAudioCall(String localProfileURI, String peerProfileURI, SipAudioCall.listener,int timeout);来创建一个SipAudioCall,其中timeout以seconds为单位,过了timeout表示打电话超时。需要打给别人时 使用makeAudioCall创建,接听电话用takeAudioCall来创建sipAudioCall
    【2】SipAudioCall中有一个嵌套的class:SipAudioCall.Listener(此类主要用于监听SIP CALL,when[呼叫电话 or 接听电话])
     

    Java Code复制内容到剪贴板
    1. SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
    2.                   @Override  
    3.                   public void onCallEstablished(SipAudioCall call) { //呼叫建立  
    4.                       call.startAudio(); //启动音频  
    5.                       call.setSpeakerMode(true); //调整为可讲话模式  
    6.                       call.toggleMute(); //触发无声  
    7.                       updateStatus(call);  
    8.                   }  
    9.   
    10.   
    11. };  
    12. SipAudioCall call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);  

    (以上例子为makeAudioCall)
    【3】我们看看makeAudioCall()方法(makeAudioCall requires 2 sipProfile):
     

    Java Code复制内容到剪贴板
    1. SipAudioCall call =new SipAudioCall(mContext, localProfile);  
    2. call.setListener(listener);  //这两句很简单就是创建一个local的sipAudioCall  
    3. SipSession s = createSipSession(localProfile, null); -->mSipService.createSession(localProfile, null);//  sipService来创建session,并保存在SipSessionGroupExt中  
    4. call.makeCall(peerProfile,s,null); //这句就是呼叫,最后追溯到实际是SipSession.makecall  

    总结:在发起通话中
    首先是创建SipAudioCall.listener,以便监听对话建立和对话结束,然后做相应的操作
    然后是SipManager.makeAudioCall(localAdd,llistener,XXXX),在makeAudioCall方法中
    A、创建一个sipAudioCall(localProfile)
    B、创建SipSession以建立起会话
    C、SipSession.makeCall(peerProfile,XXXX); //SipSession呼叫远程profile
    【4】关于接电话道理都差不多,takeAudioCall
    通过之前设置的callingID来查找mSipService.getPendingSession(callId);来获得SipSession。并创建SipAudioCall,然后attachCall就算接受电话了


    三、总结
    1、VOIP服务位于android.net.sip包中,关键类为SipManager。需要用到的permission列表,其中后面三个为使用WIFI获取IP地址所需要用到的权限:

    XML/HTML Code复制内容到剪贴板
    1. <uses-permission android:name="android.permission.INTERNET"></uses-permission>  
    2. <uses-permission android:name="android.permission.USE_SIP"/>  
    3. <uses-feature android:name = "android.hardware.sip.voip" android:required = "true"/>  
    4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
    5. <uses-permission android:name="android.permission.WAKE_LOCK" />  
    6. <uses-permission android:name="android.permission.RECORD_AUDIO" />  


    2、类之间的关系

    图片1.jpg

    图片2.jpg


    G、A~F步骤都是在做准备工作,大致的步骤如下:new SIPService-->new SIPManager-->设定用户信息-->new SIPURI-->new SIPProfile-->new PendingIntent-->set sipProfile callingID-->(if profile.getAutoRegistation)open toReceiveCalls-->register SipService
    现在是call someone~呼叫的工作是SipAudioCall类来完成(可用sipManager.makeAudioCall或takeAudioCall来 实例化,SipAudioCall.startAudio时需要 RECORD_AUDIO, ACCESS_WIFI_STATE, and WAKE_LOCK permissions,setSpeakerMode() 时需要MODIFY_AUDIO_SETTINGS permission)
    【1】当需要呼叫时,使用sipManager.makeAudioCall(String localProfileURI, String peerProfileURI, SipAudioCall.listener,int timeout);来创建一个SipAudioCall,其中timeout以seconds为单位,过了timeout表示打电话超时。需要打给别人时 使用makeAudioCall创建,接听电话用takeAudioCall来创建sipAudioCall
    【2】SipAudioCall中有一个嵌套的class:SipAudioCall.Listener(此类主要用于监听SIP CALL,when[呼叫电话 or 接听电话])
     

    Java Code复制内容到剪贴板
    1. SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
    2.                   @Override  
    3.                   public void onCallEstablished(SipAudioCall call) { //呼叫建立  
    4.                       call.startAudio(); //启动音频  
    5.                       call.setSpeakerMode(true); //调整为可讲话模式  
    6.                       call.toggleMute(); //触发无声  
    7.                       updateStatus(call);  
    8.                   }  
    9.   
    10.   
    11. };  
    12. SipAudioCall call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);  

    (以上例子为makeAudioCall)
    【3】我们看看makeAudioCall()方法(makeAudioCall requires 2 sipProfile):
     

    Java Code复制内容到剪贴板
    1. SipAudioCall call =new SipAudioCall(mContext, localProfile);  
    2. call.setListener(listener);  //这两句很简单就是创建一个local的sipAudioCall  
    3. SipSession s = createSipSession(localProfile, null); -->mSipService.createSession(localProfile, null);//  sipService来创建session,并保存在SipSessionGroupExt中  
    4. call.makeCall(peerProfile,s,null); //这句就是呼叫,最后追溯到实际是SipSession.makecall  

    总结:在发起通话中
    首先是创建SipAudioCall.listener,以便监听对话建立和对话结束,然后做相应的操作
    然后是SipManager.makeAudioCall(localAdd,llistener,XXXX),在makeAudioCall方法中
    A、创建一个sipAudioCall(localProfile)
    B、创建SipSession以建立起会话
    C、SipSession.makeCall(peerProfile,XXXX); //SipSession呼叫远程profile
    【4】关于接电话道理都差不多,takeAudioCall
    通过之前设置的callingID来查找mSipService.getPendingSession(callId);来获得SipSession。并创建SipAudioCall,然后attachCall就算接受电话了


    三、总结
    1、VOIP服务位于android.net.sip包中,关键类为SipManager。需要用到的permission列表,其中后面三个为使用WIFI获取IP地址所需要用到的权限:

    XML/HTML Code复制内容到剪贴板
    1. <uses-permission android:name="android.permission.INTERNET"></uses-permission>  
    2. <uses-permission android:name="android.permission.USE_SIP"/>  
    3. <uses-feature android:name = "android.hardware.sip.voip" android:required = "true"/>  
    4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
    5. <uses-permission android:name="android.permission.WAKE_LOCK" />  
    6. <uses-permission android:name="android.permission.RECORD_AUDIO" />  


    2、类之间的关系

    图片1.jpg

    Android Sip学习(三)Android Voip实现

    时间:2013-08-08 17:03:03  来源:束洋洋博客  作者:束洋洋

    Android Sip学习(准备知识)SIP 协议完整的呼叫流程

    Android Sip学习(一)Android 2.3 APIs SIP-based VoIP

    Android Sip学习(二)Android VoIP系统实现原理

    Android Sip学习(三)Android Voip实现

    Android Sip学习(四)Android自带SipDemo详解

    回顾下:

    一、基本概念

    1、VOIP基于SIP协议,SDK2.3包含一个SIP协议栈和框架API

    2、VOIP位于android.net.sip包中,最重要的为SipManager类,可开发基于SIP的VOIP应用。使用时要包含android.permission.INTERNET和android.permission.USE_SIP权限

    3、如果在market中显示仅支持VOIP API型号的手机的话,发布时需要在androidManifest.xml中加入<uses_feature android:name = "android.software.sip" android:required = "true">和<uses_feature android:name = "android.software.sip.voip">

    4、要支持SIP API

         (1)仅Android2.3或更高版本平台支持

         (2)不是所有设备都提供SIP支持,确保你的APP只安装在支持SIP的装置上

    5、根据GOOGLE官方DEMO项目来扩展的概念

    二、类及方法描述

    1、一个基本的VOIP项目至少需要三个类SIPSettings(对SIP的基本设置身份验证)、WalkieTalkieActivity(登 录到SIP设备供应商,注册device去处理来电,拨打电话,在通话过程中用户界面管理)、IncomingCallReceiver(监听传入的 SIP电话,然后传递这些SIP电话给WalkieTalkieActivity控制)

    2、

     WalkieTalkieActivity

    A、SipManager.newInstance()-->此方法中首先判断context是否支持SIP API,若支持则new SipManager。SipManager构造函数中,实例化了一个ISIPService(运用的公式:

    Java Code复制内容到剪贴板
    1. IBinder b =ServiceManager.getService(Context.SIP_SERVICE);  //获取系统相应的服务  
    2. ISipService service = ISipService.Stub.asInterface(bIBinder);)  

    上面这两句代码其实是使用了AIDL,就以SipService为例,步骤如下
    Service端
    1、编写aidl文件:ISipService.aidl,并定义使用的接口(就等同于interface一样)
    2、使用makefile生成与之同名的JAVA文件,SipService.java,此类继承extends ISipService.Stub并实现接口定义的方法或者在SipService extends Service,并代码中加入
    ISipService.stub sipImpl = new ISipService.stub(){
    //实现其接口方法,在SipService.java中是实现了一个名为start()的方法,里面有句是 ServiceManager.addService("sip",newSipService(context));表示SipService已经交给 ServiceManager统一管理了
    }

    Client端
    一(以SIPService为例)
    1、而在需要用到SipService时,也就是我们构造SipManager的时候,就通过ServiceManager.getService(Context.SIP_SERVICE)获得SIP的服务(类型为IBinder)
    2、并调用 ISipService.Stub.asInterface(IBinder);去获取一个SipService实例(前提是该Service一定是通过 ServiceManager.addService的方式添加进去管理的,这样才能找到此Service)


    二(以普通Activity为例)
    1、利用Intent intent = new Intent(Activity.this,SipService.class);-->bindService(intent, serviceConnection, Context.BIND_AUTO_CREATE);来绑定SERVICE,在serviceConnection的 onServiceConnected方法中,使用IService.stub.asIntentface(IBinder);来获取实例


    B、SipManager创建好后,先从SharedPreference中获取username,domain及pwd,如果第一次进来没有设置这些的 话则需要先创建账户,这里用EditTextPreference来保存用户信息,好处是当填写信息并返回后,EditTextPreference会自 动将值放入SharedPreference中。我们假设username="woody";domain="192.168.12.30"; pwd="910913"

    C、这时,我们的SipManager以及用户信息已经设定好了,接下来使用了这句SipProfile.Builder builder = new SipProfile.Builder(username, domain);我们去看看SipProfile.Builder中做了些什么:
     

    Java Code复制内容到剪贴板
    1. SipURI mUri =mAddressFactory.createSipURI(username,serverDomain);  
    2. SipProfile mProfile.mDomain=serverDomain; //设置domain  
    3. (在mAddressFactory.createSipURl方法中,我选取了一些核心代码)  
    4. StringBuffer uriString=new StringBuffer("sip:");   
    5. uriString.append(user);   
    6. uriString.append("@");   
    7. //if host is an IPv6 string we should enclose it in sq brackets  
    8. if(host.indexOf(':') !=host.lastIndexOf(':')&&host.trim().charAt(0) !='[')   
    9.    host='['+host+']';   
    10. uriString.append(host);  
    11. StringMsgParser smp=new StringMsgParser();   
    12.   
    13. SipUrl sipUri=smp.parseSIPUrl(uriString.toString());   
    14. return sipUri;  

    从以上代码可以看出其实就是在Format SipURL罢了,里面多加了个if host为IPV6的判断(IPv4为为32位,十进制;IPv6为128位,16进制)。urlString最后 为"sip:woody@192.168.12.30",smp.parseSIPUrl()方法中,有关于是如何parse的就不做阐述了,总之最后返 回了一个SipUri

    D、接下来就是SipProfile sipProfile = SipProfile.Builder.build(); //返回一个SipProfile object
    在SipProfile.Builder.build()中,设置了sipProfile的pwd值,删除了之前SipUrl对象里的 password(mUri.setUserPassword(null);)、将sipProfile的address属性设置为 AddressImpl类型的对象值、调用AddressFactory.createURI返回一个SipUri,并 sipProfile.mProxyAddress=sipUri.getHost();


    E、创建PendingIntent对象:(Intent与PendingIntent区别在于Intent是及时启动,而PendingIntent是不立刻反应,在特定的情况或通知下才启动,适用于AlertClock等)
     

    Java Code复制内容到剪贴板
    1. Intent i = new Intent();  
    2. i.setAction("android.SipDemo.INCOMING_CALL");  
    3. PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);  

    F、
    SipManager.open(sipProfile,PendingIntent,null); //(实际是SIPService在做操作)设置localSIPProfile的callingID-->建立SIP连接(算是注册至SIP Server)-->打开receiveCall
    其中建立SIP连接,最后能追溯到是在SipSessionGroup.java的reset()方法中通过是注册服务器实现的,如下图
    QQ截图20130808164903.jpg

    注册服务器的步骤为:
    (1)设置服务器的属性,例如服务器的地址(IP_ADDRESS_PROP)、栈名(javax.sip.STACK_NAME)、发出去的路径 (localProfile中的javax.sip.OUTBOUND_PROXY)、线程池的大小 (gov.nist.javax.sip.THREAD_POOL_SIZE)等,并且将这些属性加载到服务器中.
    (2)通过SipFactory的静态方法取得一个实例,然后通过SipFactory实例sipfactory
    (3)创建一个SipStack实例sipstack(这一步获得IP_ADDRESS_PROP,String address = Properties.getProperty("javax.sip.IP_ADDRESS");)
    (4)用sipstack创建一个SipProvider实例sipProvider
    (5)注册SipListener

    G、A~F步骤都是在做准备工作,大致的步骤如下:new SIPService-->new SIPManager-->设定用户信息-->new SIPURI-->new SIPProfile-->new PendingIntent-->set sipProfile callingID-->(if profile.getAutoRegistation)open toReceiveCalls-->register SipService
    现在是call someone~呼叫的工作是SipAudioCall类来完成(可用sipManager.makeAudioCall或takeAudioCall来 实例化,SipAudioCall.startAudio时需要 RECORD_AUDIO, ACCESS_WIFI_STATE, and WAKE_LOCK permissions,setSpeakerMode() 时需要MODIFY_AUDIO_SETTINGS permission)
    【1】当需要呼叫时,使用sipManager.makeAudioCall(String localProfileURI, String peerProfileURI, SipAudioCall.listener,int timeout);来创建一个SipAudioCall,其中timeout以seconds为单位,过了timeout表示打电话超时。需要打给别人时 使用makeAudioCall创建,接听电话用takeAudioCall来创建sipAudioCall
    【2】SipAudioCall中有一个嵌套的class:SipAudioCall.Listener(此类主要用于监听SIP CALL,when[呼叫电话 or 接听电话])
     

    Java Code复制内容到剪贴板
    1. SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
    2.                   @Override  
    3.                   public void onCallEstablished(SipAudioCall call) { //呼叫建立  
    4.                       call.startAudio(); //启动音频  
    5.                       call.setSpeakerMode(true); //调整为可讲话模式  
    6.                       call.toggleMute(); //触发无声  
    7.                       updateStatus(call);  
    8.                   }  
    9.   
    10.   
    11. };  
    12. SipAudioCall call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);  

    (以上例子为makeAudioCall)
    【3】我们看看makeAudioCall()方法(makeAudioCall requires 2 sipProfile):
     

    Java Code复制内容到剪贴板
    1. SipAudioCall call =new SipAudioCall(mContext, localProfile);  
    2. call.setListener(listener);  //这两句很简单就是创建一个local的sipAudioCall  
    3. SipSession s = createSipSession(localProfile, null); -->mSipService.createSession(localProfile, null);//  sipService来创建session,并保存在SipSessionGroupExt中  
    4. call.makeCall(peerProfile,s,null); //这句就是呼叫,最后追溯到实际是SipSession.makecall  

    总结:在发起通话中
    首先是创建SipAudioCall.listener,以便监听对话建立和对话结束,然后做相应的操作
    然后是SipManager.makeAudioCall(localAdd,llistener,XXXX),在makeAudioCall方法中
    A、创建一个sipAudioCall(localProfile)
    B、创建SipSession以建立起会话
    C、SipSession.makeCall(peerProfile,XXXX); //SipSession呼叫远程profile
    【4】关于接电话道理都差不多,takeAudioCall
    通过之前设置的callingID来查找mSipService.getPendingSession(callId);来获得SipSession。并创建SipAudioCall,然后attachCall就算接受电话了


    三、总结
    1、VOIP服务位于android.net.sip包中,关键类为SipManager。需要用到的permission列表,其中后面三个为使用WIFI获取IP地址所需要用到的权限:

    XML/HTML Code复制内容到剪贴板
    1. <uses-permission android:name="android.permission.INTERNET"></uses-permission>  
    2. <uses-permission android:name="android.permission.USE_SIP"/>  
    3. <uses-feature android:name = "android.hardware.sip.voip" android:required = "true"/>  
    4. <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
    5. <uses-permission android:name="android.permission.WAKE_LOCK" />  
    6. <uses-permission android:name="android.permission.RECORD_AUDIO" />  


    2、类之间的关系

    图片1.jpg

    图片2.jpg

    图片2.jpg

  • 相关阅读:
    Unity 粒子系统 特效 移除屏幕外面后再移回来 不会显示问题
    同步读取各平台StreamingAssets文件
    cocos2d-x for android 环境搭建&交叉编译
    lua 热更新
    php连接mysql超时问题
    svn仓库自动同步(主库、从库自动同步)
    游戏开发进度、状况以及结果的关系(个人感言)
    centos 重启服务命令
    编译时,输出信息重定向到文件
    vs开发的程序内存错误
  • 原文地址:https://www.cnblogs.com/timssd/p/4753724.html
Copyright © 2011-2022 走看看