Android Sip使用及坑

https://github.com/android/platform_development/tree/master/samples/SipDemo

上面是Android自带的SipDemo,下

https://developer.android.com/reference/android/net/sip/package-summary.html

Android 官网对sip的相关使用的介绍。

使用

1、注册广播

 private void registerInComingCallReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.SipDemo.INCOMING_CALL");
        callReceiver = new IncomingCallReceiver();
        this.registerReceiver(callReceiver, filter);
    }

2、实例SipManager

 if (manager == null) {
            manager = SipManager.newInstance(this);
        }

3、SipProfile

   SipProfile.Builder builder = new SipProfile.Builder("Android004", "115.236.167.22");
            builder.setPassword("78cdb4164g");
//            builder.setOutboundProxy("45.56.91.117");
            me = builder.build();

4、设置接听电话广播,如果不需要接电话可以直接manager.open(me);就可以了

  Intent i = new Intent();
            i.setAction("android.SipDemo.INCOMING_CALL");
            PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);

            manager.open(me, pi, null);

5、设置是否登录成功的监听,必须在上面的open方法之后调用

manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
                public void onRegistering(String localProfileUri) {
                //修改textview显示的文字
                    updateStatus("Registering with SIP Server...");
                }

                public void onRegistrationDone(String localProfileUri, long expiryTime) {
                    updateStatus("Ready");

                }

                public void onRegistrationFailed(String localProfileUri, int errorCode,
                                                 String errorMessage) {
                    updateStatus("Registration failed.  Please check settings.");
                }
            });

6、初始化电话

//sipaddress电话号码
  updateStatus(sipAddress);
  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();
                    updateStatus(call);
                }

                @Override
                public void onCallEnded(SipAudioCall call) {
                    updateStatus("Ready.");
                }
            };

            call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);

7、关闭SipProfile

public void closeLocalProfile() {
        if (manager == null) {
            return;
        }
        try {
            if (me != null) {
                manager.close(me.getUriString());
            }
        } catch (Exception ee) {
              Log.d( "Failed to close profile", ee.toString());
        }
    }

权限

  <uses-sdk android:minSdkVersion="10" />
    <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-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" />

receiver

   <receiver android:name=".ui.demo.sip.IncomingCallReceiver" android:label="Call Receiver"/>

坑1:WalkieTalkieActivity这个类的类名不能修改,之前试过好多次,自己创建了一个类,代码也是一样的,怎么弄都登录失败,很郁闷!不知道是不是我自己的问题。

坑2:不能设置stun,要想设置自己的stun可以使用sipdroid或者想要实现网络电话的话也可以使用开源的linphone,不过lingphone需要在linux环境下进行编译,并且下载源码编译需要翻墙,所以你必须有一个好的网络环境!

坑3:closeLocalProfile()方法最好放在opause()方法中进行调用。

坑4:安装到手机上,经常出注册失败的问题,但是重启一下手机就变成ready状态了,很无语,不知道是不是所有手机都这样,我只试了华为手机。

相对完整一点的代码

相对完整一点的代码,由于后面发现没法设置stun,所以通话的建立方法一直没能实现。InComingCall类在最开头的连接中下载即可。

public class WalkieTalkieActivity extends AppCompatActivity implements View.OnClickListener {
    private Button mButtonSipCall;
    public String sipAddress = "111";
    public SipManager manager = null;
    public SipProfile me = null;
    public SipAudioCall call = null;
    public IncomingCallReceiver callReceiver;
    private boolean isCalling = false;
    @Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.walkietalkie);
        mButtonSipCall = (Button) findViewById(R.id.btn_sipcall);
        mButtonSipCall.setOnClickListener(this);
        registerInComingCallReceiver();
    }

    private void registerInComingCallReceiver() {
        IntentFilter filter = new IntentFilter();
        filter.addAction("android.SipDemo.INCOMING_CALL");
        callReceiver = new IncomingCallReceiver();
        this.registerReceiver(callReceiver, filter);
    }

    @Override
    public void onStart() {
        super.onStart();
        initSipManager();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (call != null) {
            call.close();
        }

        closeLocalProfile();

        if (callReceiver != null) {
            this.unregisterReceiver(callReceiver);
        }
    }

    public void initSipManager() {
        if (manager == null) {
            manager = SipManager.newInstance(this);
        }
        if (manager == null) {
            return;
        }

        if (me != null) {
            closeLocalProfile();
        }
        buildSipProfile();
        setReceiveCallListener();
        setRegistrationListener();
    }
    public void buildSipProfile() {
        try {
            SipProfile.Builder builder = new SipProfile.Builder("Android", "000.000.000.000");
            builder.setPassword("abc");

            me = builder.build();
        } catch (ParseException e) {
            e.printStackTrace();
        }
    }

    private void setRegistrationListener() {
          try {
            manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
                public void onRegistering(String localProfileUri) {
                    updateStatus("Registering with SIP Server...");
                }

                public void onRegistrationDone(String localProfileUri, long expiryTime) {
                    updateStatus("Ready");
                    initiateCall();
                }

                public void onRegistrationFailed(String localProfileUri, int errorCode,
                                                 String errorMessage) {
                    updateStatus("Registration failed.  Please check settings.");
                }
            });
        } catch (SipException e) {
            e.printStackTrace();
        }
    }

    private void setReceiveCallListener() {
        try {
            Intent i = new Intent();
            i.setAction("android.SipDemo.INCOMING_CALL");
            PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);

            manager.open(me, pi, null);
        } catch (SipException e) {
            e.printStackTrace();
        }
    }
    public void closeLocalProfile() {
        if (manager == null) {
            return;
        }
        try {
            if (me != null) {
                manager.close(me.getUriString());
            }
        } catch (Exception ee) {
              Log.d( "Failed to close profile", ee.toString());
        }
    }

    /**
     * Make an outgoing call.
     */
    public void initiateCall() {
        updateStatus(sipAddress);
        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();
                    mButtonSipCall.setText("正在拨打电话");
                    updateStatus(call);
                }

                @Override
                public void onCallEnded(SipAudioCall call) {
                    updateStatus("Ready.");
                }
            };

            call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 30);

        } catch (Exception e) {
            //   Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
            if (me != null) {
                try {
                    manager.close(me.getUriString());
                } catch (Exception ee) {
//                    Log.i("WalkieTalkieActivity/InitiateCall",
//                            "Error when trying to close manager.", ee);
                    ee.printStackTrace();
                }
            }
            if (call != null) {
                call.close();
            }
        }
    }

    public void updateStatus(final String status) {
        // Be a good citizen.  Make sure UI changes fire on the UI thread.
        this.runOnUiThread(new Runnable() {
            public void run() {
                TextView labelView = (TextView) findViewById(R.id.sipLabel);
                labelView.setText(status);
            }
        });
    }

    /**
     * Updates the status box with the SIP address of the current call.
     *
     * @param call The current, active call.
     */
    public void updateStatus(SipAudioCall call) {
        String useName = call.getPeerProfile().getDisplayName();
        if (useName == null) {
            useName = call.getPeerProfile().getUserName();
        }
        updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
    }

    @Override
    public void onClick(View v) {
        if (isCalling){
            mButtonSipCall.setText("拨打电话");
            if (call != null) {
                try {
                    call.endCall();
                } catch (SipException se) {

                }
                call.close();
            }
        }else {
//            putInCallNumber();
            initiateCall();
            if (call == null) {
                return;
            }else if ( call != null && call.isMuted()) {
                call.toggleMute();
            } else if ( call.isMuted()) {
                call.toggleMute();
            }

        }
        isCalling=!isCalling;
    }

    private void putInCallNumber() {
        initiateCall();
//        LayoutInflater factory = LayoutInflater.from(this);
//        final View textBoxView = factory.inflate(R.layout.call_address_dialog, null);
//        new AlertDialog.Builder(this)
//                .setTitle("Call Someone.")
//                .setView(textBoxView)
//                .setPositiveButton(
//                        android.R.string.ok, new DialogInterface.OnClickListener() {
//                            public void onClick(DialogInterface dialog, int whichButton) {
//                                EditText textField = (EditText)
//                                        (textBoxView.findViewById(R.id.calladdress_edit));
//                                sipAddress = textField.getText().toString();
//                                initiateCall();
//
//                            }
//                        })
//                .setNegativeButton(
//                        android.R.string.cancel, new DialogInterface.OnClickListener() {
//                            public void onClick(DialogInterface dialog, int whichButton) {
//                                // Noop.
//                            }
//                        })
//                .create();
    }

}
时间: 2024-10-12 14:40:39

Android Sip使用及坑的相关文章

Android tips(十)--&gt;允许模拟位置在Android M下的坑

转载请标明出处:一片枫叶的专栏 本文我们将讲解允许模拟位置在Android M下的坑.做地图类应用的同学应该都知道为了避免软件模拟位置影响正常流程的进行我们一般都会判断用户手机是否打开了模拟位置设置,若打开了则终止用户流程,提醒用户关闭模拟位置设置.在android系统的开发者选项中有一个模拟位置的选项,其作用是允许用户通过代码模拟设备的当前位置,比如地图类应用需要测试在外地的使用情况,通过开启此项选项可以通过代码模拟位置,具体可参考我的:Android中的开发者选项 允许模拟位置的设置选项在手

Android studio 几个坑,值得注意下。

坑一:layout文件中提示(见图):(关键词检索:因为百度和google的时候都没看到这个东东,只在stackoverflow上看到这个提问,但是还没人回答.希望大家可以百度到我这条) ①:Checks references injected by IntelliLang plugin. ②:cannot fin declaration to go to . “①”产生的原因: 当光标移动到当前行时,前方会有个黄色的灯泡,我就点开了,但是不知道里边的意思是什么就点进去了,并且修改了几项内容,内

WebView中JS调用Android Method 遇到的坑整理

WebView是android中常用的一个组件,其作用是展示网页,并让网页和android app进行一些业务逻辑上的交互. 其坑无数,相信用过的都知道,一个一个来解决吧. 1.怎么互调: <!DOCTYPE> <html> <head> <meta charset="UTF-8"> <script type="text/javascript"> function android(bl){ if(bl){

Android 状态栏那些小坑?

背景:因为之前老板上次问我我们的app能不能自定义上面的状态栏我说可以啊!当时没管,今天试了下果然很多坑,之前github上也有很多大佬写了一个开源库有兴趣的可以点进去看下支持DrawLayout沉侵式[StatusBarUtil](https://github.com/laobie/StatusBarUtil)感觉好牛逼,像大佬敬礼,我毕竟是个小喽喽,我只能用最蠢的办法! 首先说下关于状态栏当系统版本为4.4或者4.4以上时可以使用沉浸式状态栏实现代码 其实状态栏这东西不是很难,就是通过添加一

[百度空间] [原]android下的各种坑

一堆so文件安装不正确: apk里面都是全的, 但是安装完后/data/data/$pkg/lib下面就没有 google了好长时间没有结果.最后发现是因为没库有加lib前缀(当时想了一下觉得不加更好,更合胃口)....现在加上lib前缀OK了. 怀疑package manager在安装apk的时候把所有没有lib prefix的so给忽略了这种剧情设定太坑爹了.不使用官方mk真是吃尽苦头啊. ndk上坑太多: dlopen()还不支持RTLD_NODELETE,又得黑代码了. apk源的/li

Android相机开发那些坑

版权声明:本文由王梓原创文章,转载请注明出处: 文章原文链接:https://www.qcloud.com/community/article/168 来源:腾云阁 https://www.qcloud.com/community 最近我负责开发了一个跟Android相机有关的需求,新功能允许用户使用手机摄像头,快速拍摄特定尺寸(1:1或3:4)的照片,并支持在拍摄出的照片上做贴纸相关的操作.由于之前没有接触过Android相机开发,所以在整个开发过程中踩了不少坑,费了不少时间和精力.这篇文章总

安卓转战React-Native之windows下android环境搭建爬坑血泪史

前言 最近又有新的项目立项,所以好久都没有写博客了,然后都是利用闲暇时间来学习React-native. 由于安卓和ios的就业环境给移动端开发带来前所未有的冲击,于是乎很多伙伴们不得不另谋他路,然后现在比较火爆的Hybird和react-native也是对我们移动端的影响比较大,比如去面试会问你会nodej或者react不,前端工程师(js)转移动端的门槛变得很低,angularjs和reactjs都很不错,并且6月底阿里开源weex,估计很多人对weex还是特别期待的,唉,只能拿知识武装自己

Android 项目开发填坑记 - 获取系统语言(兼容7.0)

如果移动端访问不佳,请访问–> Github版 关键词:Android7.0 .系统语言 .顺序不一致 获取系统当前语言是一个比较常用的功能,在 Android 7.0 系统上旧函数获取到的当前系统语言并不正确,或者说从 Android 7.0 起,Android 系统语言的规则变了. 背景 下面是未适配 Android 7.0 的代码: // 获取 Locale 的方式有二 Locale locale = getResources().getConfiguration().locale; Lo

android ndk开发爬坑之无法解析的符号

最近在公司学习ndk开发, 越学越觉得开发java比c/c++幸福多了, 至少java中,编译的时候定为的某一行的出错,那么基本上就是那一行有问题, 然而c/c++确不是这样, 我的开发环境是eclipse; 1.首先碰到的一个奇葩的问题是: Function '__builtin_bswap16' could not be resolved 这个是使用htons引起的, 搞了半天还是没解决,最后没办法只好在设置里面c/c++General:code Anallysis把这个错误给禁了, 结果成