Android Sip使用及坑

Posted danfengw

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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();
    }

}






以上是关于Android Sip使用及坑的主要内容,如果未能解决你的问题,请参考以下文章

Android Jain Sip - Sip 注册?

如何将 SIP 集成到 Android 中?

如何通过sip在android中发送短信

寻找适用于 Android 的 SIP 堆栈 [关闭]

Android 以编程方式创建 Sip 帐户

Android 在使用 Jain-SIP 库创建 SipStack 时出错