当前位置: 首页 > news >正文

Android自带SipDemo详解 4

会话发起协议 Android提供了一个支持会话发起协议(SIP)的API,这可以让你添加基于SIP的网络电话功能到你的应用程序。Android包括一个完整的SIP协议栈和集成的呼叫管理服务,让应用轻松无需管理会话和传输层的沟通就可设置传出和传入的语音通话,或直接音频记录或播放。

以下类型的应用程序可能使用SIP API: 视频会议。 即时消息。

条件和限制 以下是开发一个SIP应用程序的条件: 你必须有一个运行Android2.3或者更高版本的移动设备。 SIP是通过无线数据连接来运行的,所以你的设备必须有一个数据连接(通过移动数据服务或者Wi-Fi)。这意味着你不能在模拟器(AVD)上进行测试,只能在一个物理设备上测试。每一个参与者在应用程序的通信会话过程中必须有一个SIP账户。有很多不同的SIP服务提供商提供SIP账户。 SIP API类和接口 以下是Android SIP API中包含的一些类和一个接口(SipRegistrationListener)的概述:

类/接口
描述
 SipAudioCall 通过SIP处理网络音频电话
 SipAudioCall.Listener 关于SIP电话的事件监 听器,比如接受到一个电话(on ringing)或者呼出一个电话(on calling)的时候
 SipErrorCode 定义在SIP活动中返回的错误代码
 SipManager 为SIP任务提供APIs,比如初始化一个SIP连接。提供相关SIP服务的访问。
 SipProfile 定义了SIP的相关属性,包含SIP账户、域名和服务器信息
 SipProfile.Builder 创建SipProfile的帮助类
 SipSession 代表一个SIP会话,跟SIP对话框或者一个没有对话框的独立事务相关联
 SipSession.Listener 关于SIP会话的事件监 听器,比如注册一个会话(on registering)或者呼出一个电话(on calling)的时候
 SipSession.State 定义SIP会话的声明,比如“注册”、“呼出电话”、“打入电话”
 SipRegistrationListener 一个关于SIP注册事件监 听器的接口

 

 创建Manifest文件 如果你开发一个用到SIP API的应用程序,记住它需要Android2.3(API9)或者更高版本的平台的支持。所以在你的设备上要运行Android2.3(API9)或者更高的版本,并不是所有的设备都提供SIP的支持。 为了使用SIP,需要添加以下权限到你的manifest文件: android.permission.USE_SIP android.permission.INTERNET 为了确保你的应用程序能够安装到支持SIP的设备上,你需要添加以下内容到你应用程序的manifest文件里: <uses-sdk android:minSdkVersion="9" />.这个设置表明你的应用程序需要Android2.3或者更高版本的平台。详情请参考API Levels和<uses-sdk>元素相关的文档。 为了控制你的应用程序被那些不支持SIP的设备过滤掉(比如:在Google Play),你需要添加以下内容到你应用程序的manifest文件里: <uses-feature android:name="android.hardware.sip.voip" />. 这个设置声明了你的应用程序用到了SIP API。这个声明还应该包含一个android:required 属性来表明你是否想让你的应用程序被那些不提供SIP支持的设备过滤掉。其他<uses-feature>声明你也可能需要,具体取决于你的实现,详情请参考<uses- feature> 元素相关的文档。 如果你的应用程序设计用来接受呼叫,那么你还必须在应用程序的manifest文件里定义一个接收器(BroadcastReceiver 的子类): <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/> 以下是从SipDemo项目manifest文件中摘录的内容:

XML/HTML Code 复制内容到剪贴板
  1. <?xml version="1.0" encoding="utf-8"?>  
  2.   
  3. <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  4.           package="com.example.android.sip">  
  5. ……省略此部分
  6.   
  7.         <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>  
  8.     </application>  
  9.     <uses-sdk android:minSdkVersion="9" />  
  10.     <uses-permission android:name="android.permission.USE_SIP" />  
  11.     <uses-permission android:name="android.permission.INTERNET" />  
  12.     <uses-permission android:name="android.permission.VIBRATE" />  
  13.     <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />  
  14.     <uses-permission android:name="android.permission.WAKE_LOCK" />  
  15.     <uses-permission android:name="android.permission.RECORD_AUDIO" />  
  16.   
  17.     <uses-feature android:name="android.hardware.sip.voip" android:required="true" />  
  18.     <uses-feature android:name="android.hardware.wifi" android:required="true" />  
  19.     <uses-feature android:name="android.hardware.microphone" android:required="true" />  
  20. </manifest>  

 

创建一个SipManager对象 要想使用SIP API,你的应用程序需要创建一个SipManager对象,这个SipManager对象在你的应用程序里负责以下内容: 发起SIP会话 发起和接受呼叫 在SIP provider里进行注册和注销 验证会话的连通性

你可以像下面一样实例化一个新的SipManager对象:

Java Code 复制内容到剪贴板
  1. public SipManager mSipManager = null;  
  2. ...  
  3. if(mSipManager == null) {  
  4.     mSipManager = SipManager.newInstance(this);  
  5. }  

 

在SIP服务器上进行注册 一个典型的Android SIP应用中包含一个或多个用户,他们中的每个人都有一个SIP账户。在Android SIP应用中,每一个SIP账户代表一个SipProfile对象。 一个SipProfile对象定义了一个SIP的概要文件,包括SIP账户、域名和服务器信息。跟正在这个设备上运行应用的SIP账户相关联的概要文件被称之为本地配置文件。与会话相连接的概要文件被称之为对应配置文件。当你的SIP应用通过本地SipProfile登录到SIP服务器的时候,这就有效的注册当前设备为基站来发送SIP呼叫到你想呼叫的SIP地址。 本节展示了如何创建一个SipProfile,以及如何把刚创建的SipProfile注册到SIP服务器上,并且跟踪注册事件。 你可以像以下一样创建一个SipProfile对象:

Java Code 复制内容到剪贴板
  1. public SipProfile mSipProfile = null;  
  2. ...  
  3.   
  4. SipProfile.Builder builder = new SipProfile.Builder(username, domain);  
  5. builder.setPassword(password);  
  6. mSipProfile = builder.build();  

 

接下来的代码摘录本地配置文件,用于呼出电话和/或接收通用的SIP电话。呼叫器可以通过mSipManager.makeAudioCall来呼出后续电话。这段摘录同样设置了一个android.SipDemo.INCOMING_CALL行动,这个行动会被一个intent过滤器来使用,当前设备接收到一个呼叫。以下是注册步骤:

Java Code 复制内容到剪贴板
  1. Intent intent = new Intent();  
  2.  intent.setAction("android.SipDemo.INCOMING_CALL");  
  3.  PendingIntent pendingIntent = PendingIntent.getBroadcast(this0, intent, Intent.FILL_IN_DATA);  
  4.  mSipManager.open(mSipProfile, pendingIntent, null);  

 

最后这段代码在SipManager上设置了一个SipRegistrationListener 监 听器,这个监 听器会跟踪SipProfile是否成功的注册到你的SIP服务提供者。

Java Code 复制内容到剪贴板
  1. mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener() {  
  2.   
  3. public void onRegistering(String localProfileUri) {  
  4.     updateStatus("Registering with SIP Server...");  
  5. }  
  6.   
  7. public void onRegistrationDone(String localProfileUri, long expiryTime) {  
  8.     updateStatus("Ready");  
  9. }  
  10.   
  11. public void onRegistrationFailed(String localProfileUri, int errorCode,  
  12.     String errorMessage) {  
  13.     updateStatus("Registration failed.  Please check settings.");  
  14. }  

 

当你的应用程序使用完一个profile的时候,你应该关闭它来释放相关联的对象到内存中以及从服务器上注销当前设备。例如:

Java Code 复制内容到剪贴板
  1. public void closeLocalProfile() {  
  2.     if (mSipManager == null) {  
  3.       return;  
  4.     }  
  5.     try {  
  6.        if (mSipProfile != null) {  
  7.           mSipManager.close(mSipProfile.getUriString());  
  8.        }  
  9.      } catch (Exception ee) {  
  10.        Log.d("WalkieTalkieActivity/onDestroy""Failed to close local profile.", ee);  
  11.      }  
  12. }  

 

拨打一个语音电话 要想拨打一个语音电话,你需要准备如下条件: 一个发起呼叫电话的SipProfile对象(本地配置文件)和一个用来接收呼叫的有效的SIP地址(对应配置文件); 一个SipManager对象。

要想拨打一个语音电话,你应该建立一个SipAudioCall.Listener监 听器。大部分客户与SIP堆栈的交互都是通过监 听器来发生的。在这一小段你将会看到SipAudioCall.Listener监 听器是如何在呼叫制定之后建立事务的:

Java Code 复制内容到剪贴板
  1. SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
  2.   
  3.    @Override  
  4.    public void onCallEstablished(SipAudioCall call) {  
  5.       call.startAudio();  
  6.       call.setSpeakerMode(true);  
  7.       call.toggleMute();  
  8.          ...  
  9.    }  
  10.   
  11.    @Override  
  12.    public void onCallEnded(SipAudioCall call) {  
  13.       // Do something.  
  14.    }  
  15. };  

 

一旦你创建了这个SipAudioCall.Listener监 听器,你就可以拨打电话了,SipManager对象里的makeAudioCall方法接受以下参数:

一个本地SIP配置文件(呼叫方) 一个相对应的SIP配置文件(被呼叫方) 一个用来监听从SipAudioCall发出的呼叫事件的SipAudioCall.Listener,这个参数可以为null,但是如上所说,一旦呼叫电话制定,这个监 听器将被用来创建事务 (超时的值,以秒为单位)

例如:

Java Code 复制内容到剪贴板
  1. call = mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress, listener, 30);  

 

接收呼叫 为了接收呼叫,SIP应用程序必须包含一个BroadcastReceiver的子类,这个子类得有能力响应一个表明有来电的intent。因此你需要在你的应用程序里做如下事情: 在AndroidManifest.xml文件中声明一个<receiver>元素。在SipDemo项目中,<receiver>元素是这样的<receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/> 实现BroadcastReceiver的子类,在SipDemo中,这个子类是IncomingCallReceiver 通过挂起一个intent来初始化本地配置文件(SipProfile),当有人呼叫你的时候,这个挂起的intent会调用你的接收器。 创建一个intent过滤器,这个过滤器通过标志着来电的行动来进行过滤。在SipDemo中,这个action是android.SipDemo.INCOMING_CALL

实现BroadcastReceiver的子类 为了接收呼叫,你的SIP应用必须实现BroadcastReceiver的子类。当Android系统接收到一个呼叫的时候,他会处理这个SIP呼叫,然后广播一个来电intent(这个intent由系统来定义),以下是SipDemo中实现BroadcastReceiver子类的代码。(如果想查看完整的例子,你可以下载官网的SDK,里面自带例子从android-10就开始有这个功能,下面是我的电脑截图)

QQ截图20130814145342.jpg

Java Code 复制内容到剪贴板
  1. /*** Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. 
  2.  */  
  3. public class IncomingCallReceiver extends BroadcastReceiver {  
  4.     /** 
  5.      * Processes the incoming call, answers it, and hands it over to the 
  6.      * WalkieTalkieActivity. 
  7.      * @param context The context under which the receiver is running. 
  8.      * @param intent The intent being received. 
  9.      */   
  10.     @Override  
  11.     public void onReceive(Context context, Intent intent) {  
  12.         SipAudioCall incomingCall = null;  
  13.         try {  
  14.             SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
  15.                 @Override  
  16.                 public void onRinging(SipAudioCall call, SipProfile caller) {  
  17.                     try {  
  18.                         call.answerCall(30);  
  19.                     } catch (Exception e) {  
  20.                         e.printStackTrace();  
  21.                     }  
  22.                 }  
  23.             };  
  24.             WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;  
  25.             incomingCall = wtActivity.mSipManager.takeAudioCall(intent, listener);  
  26.             incomingCall.answerCall(30);  
  27.             incomingCall.startAudio();  
  28.             incomingCall.setSpeakerMode(true);  
  29.             if(incomingCall.isMuted()) {  
  30.                 incomingCall.toggleMute();  
  31.             }  
  32.             wtActivity.call = incomingCall;  
  33.             wtActivity.updateStatus(incomingCall);  
  34.         } catch (Exception e) {  
  35.             if (incomingCall != null) {  
  36.                 incomingCall.close();  
  37.             }  
  38.         }  
  39.     }  
  40. }  

 

创建一个用来接收呼叫的intent过滤器 当SIP服务接收到一个新的呼叫的时候,他会发送一个intent,这个intent会附带一个由应用程序提供的action。在SipDemo项目中,这个action是android.SipDemo.INCOMING_CALL。 以下从SipDemo中摘录的代码展示了如何通过挂起一个基于android.SipDemo.INCOMING_CALL action的intent来创建SipProfile对象的。PendingIntent对象将执行一个广播当SipProfile接收到一个呼叫的时候:

Java Code 复制内容到剪贴板
  1. public SipManager mSipManager = null;  
  2. public SipProfile mSipProfile = null;  
  3. ...  
  4.   
  5. Intent intent = new Intent();   
  6. intent.setAction("android.SipDemo.INCOMING_CALL");   
  7. PendingIntent pendingIntent = PendingIntent.getBroadcast(this0, intent, Intent.FILL_IN_DATA);   
  8. mSipManager.open(mSipProfile, pendingIntent, null);  

 

上面被执行的广播如果被intent过滤器拦截的话,这个intent过滤器将会启动声明过的Receiver(IncomingCallReceiver)。你可以在你的应用程序里的manifest文件中指定一个intent过滤器,或者通过代码来指定一个intent过滤器,就像SipDemo项目中Activity中的onCreate()方法一样:

Java Code 复制内容到剪贴板
  1. public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {  
  2. ...  
  3.     public IncomingCallReceiver callReceiver;  
  4.     ...  
  5.   
  6.     @Override  
  7.     public void onCreate(Bundle savedInstanceState) {  
  8.   
  9.        IntentFilter filter = new IntentFilter();  
  10.        filter.addAction("android.SipDemo.INCOMING_CALL");  
  11.        callReceiver = new IncomingCallReceiver();  
  12.        this.registerReceiver(callReceiver, filter);  
  13.        ...  
  14.     }  
  15.     ...  
  16. }  

 

测试SIP应用程序 要测试SIP应用程序的话,你需要以下条件: 一个运行Android2.3或者更高版本的移动设备。SIP通过无线来运行,所以你必须在一个真正的设备上测试,在AVD上是测试是行不通的 一个SIP账户,有很多不同的提供SIP账户的SIP服务提供商。 如果你要打电话,这个电话必须是有效的SIP账户。 测试一个SIP应用程序的步骤: 让你的设备连接到无线(设置>无线&网络>Wi-Fi>Wi-Fi设置) 设置你的移动设备进行测试,就像在Developing on a Device里描述的一样 在你的移动设备上运行程序,就像在Developing on a Device里描述的一样 如果你正在使用Eclipse,你可以在Eclipse中查看应用程序的日志输出(Window > Show View > Other > Android > LogCat)。

相关文章:

  • nodejs小问题拾遗
  • 李寒峰:微信支付-无法阻挡的生活潮流
  • 20.34 批量远程执行命令
  • Linux hosts.allow与hosts.deny文件设置
  • 来分享一个我自己写的HTML模板引擎,Leopard
  • VS2010下静态链接FreeImage
  • 网站开放平台发布-开创应用个人创业
  • python自动化学习笔记(八)
  • 毕业设计记录(四)一个form里有两个image的input提交按钮,servlet咋处理?
  • 关联容器
  • Hibernate注解方式的抓取策略
  • GNU gcc package link
  • 你不知道的JavaScript-原型
  • socket编程入门教程(三)TCP原理:5、TCP的三次握手three-way handshake
  • 构建二叉树进行数值数组的去重及优化
  • [数据结构]链表的实现在PHP中
  • Asm.js的简单介绍
  • ECMAScript入门(七)--Module语法
  • ES6--对象的扩展
  • Fundebug计费标准解释:事件数是如何定义的?
  • Lucene解析 - 基本概念
  • Material Design
  • orm2 中文文档 3.1 模型属性
  • React Native移动开发实战-3-实现页面间的数据传递
  • 构造函数(constructor)与原型链(prototype)关系
  • 在Docker Swarm上部署Apache Storm:第1部分
  • No resource identifier found for attribute,RxJava之zip操作符
  • 正则表达式-基础知识Review
  • 专访Pony.ai 楼天城:自动驾驶已经走过了“从0到1”,“规模”是行业的分水岭| 自动驾驶这十年 ...
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​html.parser --- 简单的 HTML 和 XHTML 解析器​
  • # MySQL server 层和存储引擎层是怎么交互数据的?
  • #HarmonyOS:Web组件的使用
  • #if 1...#endif
  • (3)nginx 配置(nginx.conf)
  • (31)对象的克隆
  • (C语言)编写程序将一个4×4的数组进行顺时针旋转90度后输出。
  • (day6) 319. 灯泡开关
  • (十一)手动添加用户和文件的特殊权限
  • (转)四层和七层负载均衡的区别
  • (轉貼) 資訊相關科系畢業的學生,未來會是什麼樣子?(Misc)
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .net2005怎么读string形的xml,不是xml文件。
  • .Net通用分页类(存储过程分页版,可以选择页码的显示样式,且有中英选择)
  • .NET应用架构设计:原则、模式与实践 目录预览
  • .sh 的运行
  • @reference注解_Dubbo配置参考手册之dubbo:reference
  • @Valid和@NotNull字段校验使用
  • [Android]创建TabBar
  • [BZOJ2208][Jsoi2010]连通数
  • [BZOJ4016][FJOI2014]最短路径树问题
  • [C#]OpenCvSharp使用帧差法或者三帧差法检测移动物体
  • [CSS]盒子模型
  • [Err] 1055 - Expression #1 of ORDER BY clause is not in GROUP BY clause and contains nonaggregated c
  • [ERROR]-Error: failure: repodata/filelists.xml.gz from addons: [Errno 256] No more mirrors to try.