SIP for android

SIP for android

 

会话发起协议

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


以下类型的应用程序可能使用SIP API:

  • 视频会议。
  • 即时消息。

条件和限制

以下是开发一个SIP应用程序的条件:

  • 你必须有一个运行Android2.3或者更高版本的移动设备。
  • SIP是通过无线数据连接来运行的,所以你的设备必须有一个数据连接(通过移动数据服务或者Wi-Fi)。这意味着你不能在模拟器(AVD)上进行测试,只能在一个物理设备上测试。详情请参见应用程序测试(Testing SIP Applications)。
  • 每一个参与者在应用程序的通信会话过程中必须有一个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] view plaincopyprint?
  1.    
  2.  <?xml version="1.0" encoding="utf-8"?>  
  3.  <manifest xmlns:android="http://schemas.android.com/apk/res/android"  
  4.            package="com.example.android.sip">  
  5.    ...       
  6.       <receiver android:name=".IncomingCallReceiver" android:label="Call Receiver"/>    
  7.    ...  
  8.    <uses-sdk android:minSdkVersion="9" />  
  9.    <uses-permission android:name="android.permission.USE_SIP" />  
  10.    <uses-permission android:name="android.permission.INTERNET" />  
  11.    ...  
  12.    <uses-feature android:name="android.hardware.sip.voip" android:required="true" />  
  13.    <uses-feature android:name="android.hardware.wifi" android:required="true" />  
  14.    <uses-feature android:name="android.hardware.microphone" android:required="true" />  
  15.  </manifest>  
  16.    

创建一个SipManager对象

要想使用SIP API,你的应用程序需要创建一个SipManager对象,这个SipManager对象在你的应用程序里负责以下内容:

  • 发起SIP会话
  • 发起和接受呼叫
  • 在SIP provider里进行注册和注销
  • 验证会话的连通性

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

[java] view plaincopyprint?
  1.    
  2.  public SipManager mSipManager = null;  
  3.  ...  
  4.  if(mSipManager == null) {  
  5.      mSipManager = SipManager.newInstance(this);  
  6.  }  

在SIP服务器上进行注册

一个典型的Android SIP应用中包含一个或多个用户,他们中的每个人都有一个SIP账户。在Android SIP应用中,每一个SIP账户代表一个SipProfile对象。

一个SipProfile对象定义了一个SIP的概要文件,包括SIP账户、域名和服务器信息。跟正在这个设备上运行应用的SIP账户相关联的概要文件被 称之为本地配置文件。与会话相连接的概要文件被称之为对应配置文件。当你的SIP应用通过本地SipProfile登录到SIP服务器的时候,这就有效的 注册当前设备为基站来发送SIP呼叫到你想呼叫的SIP地址。

本节展示了如何创建一个SipProfile,以及如何把刚创建的SipProfile注册到SIP服务器上,并且跟踪注册事件。 你可以像以下一样创建一个SipProfile对象:

[java] view plaincopyprint?
  1.    
  2. public SipProfile mSipProfile = null;  
  3.  ...  
  4.    
  5.  SipProfile.Builder builder = new SipProfile.Builder(username, domain);  
  6.  builder.setPassword(password);  
  7.  mSipProfile = builder.build();  

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

[java] view plaincopyprint?
  1.    
  2.   Intent intent = new Intent();  
  3.  intent.setAction("android.SipDemo.INCOMING_CALL");  
  4.  PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);  
  5.  mSipManager.open(mSipProfile, pendingIntent, null);  
  6.    

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

[java] view plaincopyprint?
  1.    
  2. mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener() {  
  3.    
  4.  public void onRegistering(String localProfileUri) {  
  5.      updateStatus("Registering with SIP Server...");  
  6.  }  
  7.    
  8.  public void onRegistrationDone(String localProfileUri, long expiryTime) {  
  9.      updateStatus("Ready");  
  10.  }  
  11.    
  12.  public void onRegistrationFailed(String localProfileUri, int errorCode,  
  13.      String errorMessage) {  
  14.      updateStatus("Registration failed.  Please check settings.");  
  15.  }<span style="padding:0px; margin:0px; color:rgb(102,204,102)"></span>  
  16.    

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

[java] view plaincopyprint?
  1.    
  2.  public void closeLocalProfile() {  
  3.      if (mSipManager == null) {  
  4.        return;  
  5.      }  
  6.      try {  
  7.         if (mSipProfile != null) {  
  8.            mSipManager.close(mSipProfile.getUriString());  
  9.         }  
  10.       } catch (Exception ee) {  
  11.         Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);  
  12.       }  
  13.  }  
  14.    

拨打一个语音电话

要想拨打一个语音电话,你需要准备如下条件:

  • 一个发起呼叫电话的SipProfile对象(本地配置文件)和一个用来接收呼叫的有效的SIP地址(对应配置文件)
  • 一个SipManager对象

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

[java] view plaincopyprint?
  1.    
  2.  SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
  3.    
  4.     @Override  
  5.     public void onCallEstablished(SipAudioCall call) {  
  6.        call.startAudio();  
  7.        call.setSpeakerMode(true);  
  8.        call.toggleMute();  
  9.           ...  
  10.     }  
  11.    
  12.     @Override  
  13.     public void onCallEnded(SipAudioCall call) {  
  14.        // Do something.  
  15.     }  
  16.  };  
  17.    

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

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

例如:

 

[html] view plaincopyprint?
  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子类的代码。如果想查看 完整的例子,你可以去SipDemo Sample项目,这个项目在SDK的samples文件夹中。关于下载和安装SDK samples,请参考 Getting the Samples。

[java] view plaincopyprint?
  1.    
  2. /*** Listens for incoming SIP calls, intercepts and hands them off to WalkieTalkieActivity. 
  3.   */  
  4.  public class IncomingCallReceiver extends BroadcastReceiver {  
  5.      /** 
  6.       * Processes the incoming call, answers it, and hands it over to the 
  7.       * WalkieTalkieActivity. 
  8.       * @param context The context under which the receiver is running. 
  9.       * @param intent The intent being received. 
  10.       */   
  11.      @Override  
  12.      public void onReceive(Context context, Intent intent) {  
  13.          SipAudioCall incomingCall = null;  
  14.          try {  
  15.              SipAudioCall.Listener listener = new SipAudioCall.Listener() {  
  16.                  @Override  
  17.                  public void onRinging(SipAudioCall call, SipProfile caller) {  
  18.                      try {  
  19.                          call.answerCall(30);  
  20.                      } catch (Exception e) {  
  21.                          e.printStackTrace();  
  22.                      }  
  23.                  }  
  24.              };  
  25.              WalkieTalkieActivity wtActivity = (WalkieTalkieActivity) context;  
  26.              incomingCall = wtActivity.mSipManager.takeAudioCall(intent, listener);  
  27.              incomingCall.answerCall(30);  
  28.              incomingCall.startAudio();  
  29.              incomingCall.setSpeakerMode(true);  
  30.              if(incomingCall.isMuted()) {  
  31.                  incomingCall.toggleMute();  
  32.              }  
  33.              wtActivity.call = incomingCall;  
  34.              wtActivity.updateStatus(incomingCall);  
  35.          } catch (Exception e) {  
  36.              if (incomingCall != null) {  
  37.                  incomingCall.close();  
  38.              }  
  39.          }  
  40.      }  
  41.  }<span style="padding:0px; margin:0px; color:rgb(102,204,102)"></span>  
  42.    

创建一个用来接收呼叫的intent过滤器

当SIP服务接收到一个新的呼叫的时候,他会发送一个intent,这个intent会附带一个由应用程序提供的action。在SipDemo项目中,这个action是android.SipDemo.INCOMING_CALL。

以下从SipDemo中摘录的代码展示了如何通过挂起一个基于android.SipDemo.INCOMING_CALL action的intent来创建SipProfile对象的。PendingIntent对象将执行一个广播当SipProfile接收到一个呼叫的时 候:

[java] view plaincopyprint?
  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(this, 0, intent, Intent.FILL_IN_DATA);   
  8.  mSipManager.open(mSipProfile, pendingIntent, null);  

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

[java] view plaincopyprint?
  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)。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/296579.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

饿了么翻车,美团被质疑,马云也赔了40亿,这项技术为什么让人害怕?

全世界只有3.14 % 的人关注了爆炸吧知识人类还没用力AI可能就倒下了8日&#xff0c;一篇《外卖骑手&#xff0c;困在系统里》的文章刷爆了朋友圈。看过的人多半都不好受&#xff0c;除了作为社畜感叹生活不易外&#xff0c;就是感叹外卖系统的AI算法对人类的裹挟是那么的残酷。…

如何强制 .NET 程序以 管理员模式 运行 ?

咨询区 Gold&#xff1a;我有一个 winform 程序部署客户的PC机上&#xff0c;请问我如何通过编码的形式强制让程序以管理员模式运行&#xff1f;回答区 Gaspa79&#xff1a;如果你用的是 Visual Studio 2019&#xff0c;可以通过工具去配置&#xff0c;右键 项目 -> 新建项 …

bitmap 转byte[]后读取_闲谈redis的bitmap

bitmap的原理bitmap就是通过最小的单位bit(8bit 1b 0.001kb)来进行0或者1的设置&#xff0c;表示某个元素对应的值或者状态。一个bit的值&#xff0c;或者是0&#xff0c;或者是1&#xff1b;也就是说一个bit能存储的最多信息是2。优点基于最小的单位bit进行存储&#xff0c;…

序1--年轻正当时(特权)

序1 年轻正当时 这本所谓的书&#xff0c;恐怕不一定能够带还没入门的U杀进FPGA开发的大门&#xff0c;当然也肯定不能达到进阶的目的。但是&#xff0c;姑且应了Bingo老弟所谓的对“图像的直觉”&#xff0c;确实图文并茂的从某一个山寨面把FPGA开发赤裸裸的展现给了大家。 被…

ecshop在首页调用dedecms文章

ecshop的文章功能实在是太过于简单了&#xff0c;所以我们为了丰富网站的内容&#xff0c;一般会集成DEDECMS来添加一些资讯文章&#xff0c;主要是DEDECMS文章处理相当强大&#xff0c;便于二次开发&#xff0c;下面通过两大步骤实现ecshop在首页调用dedecms文章&#xff1a;一…

Windows 11 dapr 环境安装

安装其实很简单按照dapr官网操作步骤其实没什么大问题的,不过在没有好的网络访问github的情况下真是有点揪心啦&#xff01;推荐使用 工具 fastgithub 访问githubFast&#xff1a;Github让Github畅通无阻windows 11 下的安装方式1.安装dapr cli 直接到Releases dapr/cli GitH…

eclipse 运行MapReduce程序错误异常汇总(解决Map not fount)

错误一&#xff1a; Error: java.lang.RuntimeException: java.lang.ClassNotFoundException: Class wordCount.wordCount$Map not foundat org.apache.hadoop.conf.Configuration.getClass(Configuration.java:2074)at org.apache.hadoop.mapreduce.task.JobContextImpl.getMa…

日本原装进口雪平锅,煎炸炒煮全搞定,日本人用了 1000 年

▲ 点击查看小爆我虽然热爱烹饪&#xff0c;但不得不说「下厨房」&#xff0c;也是个坑。光是锅&#xff0c;我就要买好几个。为了蒸包子馒头买蒸锅&#xff0c;为了炒菜买炒锅&#xff0c;偶尔想精致喝热牛奶又买了小奶锅&#xff0c;为了煲汤、做点卤味解解馋&#xff0c;买炖…

Android开发学习笔记:浅谈Content Provider

一.Content Provider的概念介绍 Content Providers是所有应用程序之间数据存储和检索的桥梁&#xff0c;它使得各个应用程序之间实现数据共享。是应用程序间共享数据的唯一途径。Content Provider 主要的功能就是存储并检索数据以及向其他应用程序提供访问数据的接口。其中包括…

小米3g刷高格固件_小米路由器3G刷了老毛子之后恢复官方固件

这个教程我没有亲自试过,看到了只是为了保存记录一下,方便自己日后用!1、断电路由器后&#xff0c;按住Reset恢复出厂设置5秒&#xff0c;接入电源&#xff0c;灯闪烁三下后松开。浏览器输入192.168.1.1即可进入breed 控制台&#xff01;2、固件更新-Bootloader-选择Bootloader…

VS2010插件之NuGet

Visual Studio&#xff08;简写VS&#xff09;是.net程序员开发必不可少的开发工具&#xff0c;随着VS的版本不断的升级和使用用户的扩大&#xff0c;现在针对VS开发了许多的开源免费的插件&#xff0c;大大的方便了程序员的开发&#xff0c;提高了开发效率。今天&#xff0c;我…

C# WPF Caliburn.Micro框架下利用Mef加载其它项目界面

01—前言MEF是微软自家的托管可扩展框架&#xff0c;在这里我把它用成了ioc容器。在Caliburn.Micro框架下&#xff0c;view和viewmodel被注入到CompositionContainer容器中&#xff0c;然后通过名称可以实现view和viewmodel的匹配。利用这一特点&#xff0c;在多人合作项目开发…

thinkpade450装内存条_thinkpad e450可以加内存条吗

展开全部结论&#xff1a;肯定是可以加的。原因62616964757a686964616fe59b9ee7ad9431333361313362&#xff1a;thinkpad e450自带两个内存插槽&#xff0c;最高可扩展至16G内存&#xff0c;也就是插两根8G内存条&#xff0c;这款笔记本增加内存的话&#xff0c;建议插两根4G的…

女朋友竟然提出这种奇怪的要求......

1 为什么女朋友会提这么奇怪的要求&#xff1f;▼2 我的数学能力▼3 一看就是老龙人了阁下是古墓派传人吧▼4 如果可爱能晋级的话你已经赢了▼5 要做个与众不同的垃圾▼6 女孩子喜欢帅哥是不分年龄的▼‍‍7 单身狗又做错了什么呢&#xff1f;▼扫描这个二维码你将会有机…

java内存:堆、栈、常量池、方法区

java中内存主要包含4块&#xff0c;即heap(堆内存)、stack(栈内存)、data segment(静态变量或是常量存放区)、codesegment(方法区). 参考&#xff1a; http://jameszhao1987.iteye.com/blog/1320630转载于:https://www.cnblogs.com/zhouqg/p/4758422.html

Java编码规范,在您进行编码之前应该阅读的规范

为什么80%的码农都做不了架构师&#xff1f;>>> 本文转载于&#xff1a;http://www.web3d.com.cn/new/teach/java3d/2006/11/13/363276161.html Java编码规范 说明 1.1 为什么要有编码规范 编码规范对于程序员而言尤为重要&#xff0c;有以下几个原因&#xff1a; …

ensp查看历史配置命令_华为eNSP常用命令

开启DHCP功能[R1-GigabitEthernet0/0/2]dhcp select interface开启接口的DHCP服务功能[R1-GigabitEthernet0/0/2]dhcp server lease day 2配置IP地址租用有效期限为2天,默认为1天,超过租期后该地址将会重新分配[R1-GigabitEthernet0/0/2]dhcp server excluded-ip-address 192.1…

.NET Core 如何调试 CPU 爆高?

在这篇文章中我们将会分析一个 CPU 爆高的案例&#xff0c;测试demo链接 &#xff1a;https://docs.microsoft.com/en-us/samples/dotnet/samples/diagnostic-scenarios/ 。你将会学到&#xff1a;如何使用 dotnet-counters 确定真实的 cpu 使用率。使用 dotnet-trace 追踪代码…

[OIBH] 糖果盒(Candy Box)——又一个最大子矩形

http://codewaysky.sinaapp.com/problem.php?id1056 这题和奶牛浴场略有区别&#xff0c;奶牛浴场只需要求出最大子矩形&#xff0c;而这题要求的是最大权重子矩形&#xff0c;不一定要最大的面积&#xff0c;但要最大的权重和 思路是先求出每个最大子矩形&#xff0c;然后求出…

百度面试

1 算法&#xff1a;写LRU算法 2 算法思想&#xff0c;二维矩阵中查找一个数&#xff0c;矩阵的按行递增和按列递增。 3 将int i的一个数转换为大端形式&#xff0c;例如0x1a2b3c4d为0x4d3c2b1a。 4 已知一随机发生器&#xff0c;产生0的概率是p&#xff0c;产生1的概率是1-p&am…