android sip协议通话实现

android sip协议通话代码实现

  • 简介
    • android里面的VOIP网络通话基于sip(Session initiation protocol)协议;android已经集成了sip协议栈,并提供了相应的API给应用开放使用,开发者不需要了解具体的协议内容

  • 基于sip的网络通话基本过程

    1. 建立SIP服务器,关于如何建立SIP服务器,请参考这篇文章
    2. 需要所有参与通话的客户端注册用户到SIP服务器
    3. 一个客户端发起SIP通话到另一个客户端,这个消息首先发到SIP服务器,sip服务器收到消息后转发到目的客户端
    4. 目的客户端接收电话

  • 关于SIP网络通话的主要类和描述如下表所示:

    <table>
    <tbody><tr>
    <th>类/接口</th>
    <th>描述</th>

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

<tr>
<th> SipSession.State</th>
<th>定义SIP会话的声明,比如“注册”、“呼出电话”、“打入电话”</th>
</tr>
<tr>
<th> SipRegistrationListener</th>
<th> 一个关于SIP注册事件监 听器的接口</th></tr></tbody></table>


  • 在应用的AndroidManifest.xml中需要声明下面权限和特征

      <uses-permission android:name="android.permission.USE_SIP" />
      <uses-permission android:name="android.permission.INTERNET" />
      <uses-permission android:name="android.permission.VIBRATE" />
      <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
      <uses-permission android:name="android.permission.WAKE_LOCK" />
      <uses-permission android:name="android.permission.RECORD_AUDIO" />
      <uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
      
      <uses-feature android:name="android.hardware.sip.voip" android:required="true" />
      <uses-feature android:name="android.hardware.wifi" android:required="true" />
      <uses-feature android:name="android.hardware.microphone" android:required="true" />
    

  • 构造一个SipManager实例.

      SipManager manager = SipManager.newInstance(this);
      //必须调用此方法创建,这是因为该方法会判断设备是否支持sip协议PackageManager.FEATURE_SIP
      如果有的android设备不支持,可以添加android.software.sip.voip.xml和android.software.sip.xml到/system/etc/permissions/下
    

  • 下面代码是注册一个账户到SIP服务器
    SipProfile.Builder builder = new SipProfile.Builder(username, domain); 
    //uesrname表示注册用户名,domain表示域,实际就是sip服务器ip
    builder.setPassword(password); //注册用户密码
    SipProfile me = builder.build(); //构造一个SipProfile对象,也就是相当于一个账户信息
    Intent i = new Intent();
    i.setAction("android.SipDemo.INCOMING_CALL");
    PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA); 
    //构造一个PendingIntent对象,这样当sip Service收到一个通话请求时,
    //例如收到一个来电时,SipService会调用PendingIntent的send方法发送相应广播消息给调用者,也就是当前的SipProfile对象.
    manager.open(me, pi, null); //此处就是用于注册一个账户到sip服务器

//注册一个监听器,用于获取注册账户时的通知状态,当然也可以不注册.

        manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
        public void onRegistering(String localProfileUri) { //正在注册
        }

        public void onRegistrationDone(String localProfileUri, long expiryTime) {//注册成功
        }

        public void onRegistrationFailed(String localProfileUri, int errorCode,
                String errorMessage) {
        }
    });

  • 开始拨号,从一个设备拨打电话到另一个设备,前提是两个设备都已注册,且知道目的设备的sip账户信息.

      try {
          SipAudioCall.Listener listener = new SipAudioCall.Listener() {
              // Much of the client's interaction with the SIP Stack will
              // happen via listeners.  Even making an outgoing call, don't
              // forget to set up a listener to set things up once the call is established.
              @Override
              public void onCallEstablished(SipAudioCall call) { //当网络通话建立了之后,会收到此通知
                  call.startAudio(); //启动音频
                  call.setSpeakerMode(true); //设置为扬声器模式,也就是开启回声抑制
                  call.toggleMute(); //切换静音,注意默认为非静音,调用此方法后变为静音了
              }
      
              @Override
              public void onCallEnded(SipAudioCall call) {
              }
          };
      
          //注意此处的makeAudioCall方法就是打网络电话的,localProfile就是本地设备的SipProfile对象,
          //PeerProfile就是目标设备的SipProfile对象,listener是监听器
              SipAudioCall call = manager.makeAudioCall(localProfile.getUriString(),
               PeerProfile, listener, 30);}catch (Exception e) {    }
    
    • 注意,此处的SipProfile的内容格式,例如,LocalProfile的url格式为"sip:abcde123@10.0.149.240",PeerProfile的url格式为"sip:abcde234@10.0.149.240",url内容也就是sip账户,
      其中:

        (1)  sip: 表示采用sip协议
        (2) abcde123和abcde234是用户名, 也称为帐号.  用字母和数字均可。
        (3) 10.0.149.240是sip账户所属的服务器地址(当然也可以用域名来表示)
        (4)  SIP协议默认端口为5060,  默认采用UDP传输,如果需要指定端口为5678,可以修改为sip:abcde123@10.0.149.240:5678,
      

从localProfile和peerProfile指定的内容可以看出,账户名作为唯一标识,由sip服务器来解析账户名,从而找到对应的目的主机.

  • 目的端接收通话
    • 根据前面的分析,一个设备拨打电话到目的设备时,在目的设备的sip服务(SipService)会发送一个广播消息给当前的目的设备。因此必须提前注册一个广播接收器来接收此消息,这样才知道有来电通知,可以在AndroidManifest.xml静态注册,也可以在应用程序中动态注册,因此下面代码必须放在广播接收器的onReceive()方法中:

    • 案例:

      try {

        SipAudioCall.Listener listener = new SipAudioCall.Listener() {
            @Override
            public void onRinging(SipAudioCall call, SipProfile caller) {
                try {
                    call.answerCall(30);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
      
        //takeAudioCall就表示需要为接听电话创建一个SipAudioCall对象.
        SipAudioCall incomingCall = manager.takeAudioCall(intent, listener);
        incomingCall.answerCall(30); //接听电话
        incomingCall.startAudio(); //启动音频
        incomingCall.setSpeakerMode(true);
      
      • 注意点:

              1.所有参与网络通话的设备和sip服务器的网络必须是连接的,网络类型可以是以太网,wifi,mobile等都可以.
              如果通话过程有问题,可以检测设备网络收发包是否正常.
              2.对应的设备必须支持sip,voip功能才行.
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 205,386评论 6 479
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,939评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,851评论 0 341
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,953评论 1 278
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,971评论 5 369
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,784评论 1 283
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,126评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,765评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,148评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,744评论 2 323
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,858评论 1 333
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,479评论 4 322
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,080评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,053评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,278评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,245评论 2 352
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,590评论 2 343