Android Sip使用及坑

知识的价值不在于占有,而在于使用。这篇文章主要讲述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状态了,很无语,不知道是不是所有手机都这样,我只试了华为手机。
相对完整一点的代码【Android Sip使用及坑】相对完整一点的代码,由于后面发现没法设置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(); }}








    推荐阅读