I have created sip application using native sip in android .In it I am getting problem in unregistering account from sip server and every time I am getting DATA_CONNECTION_LOST .I also see in android docs ,but there is no brief explanation of this error.Also it facing various erros while regiterin like in_progress ,transaction_terminated etc which are not having proper explainations in doc . Here is my code :
import android.app.Activity;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.preference.PreferenceManager;
import android.util.Log;
import android.view.*;
import android.widget.Chronometer;
import android.net.sip.*;
import java.text.ParseException;
import commonUtilities.Prefs;
public class WalkieTalkieActivity extends Activity implements View.OnTouchListener {
public String sipAddress = null;
public SipManager manager = null;
public SipProfile me = null;
public SipAudioCall call = null;
public SipErrorCode sipcode;
public SipException sipexeception;
public static WalkieTalkieActivity walkiy;
public static WalkieTalkieActivity getInstance(Context c) {
if (walkiy == null) {
walkiy = new WalkieTalkieActivity();
}
return walkiy;
}@
Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// "Push to talk" can be a serious pain when the screen keeps turning off.
// Let's prevent that.
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
Log.e("onCreate", "onCreate");
initializeManager(this);
}@
Override
public void onStart() {
super.onStart();
// When we get back from the preference setting Activity, assume
// settings have changed, and re-login with new auth info.
initializeManager(this);
}@
Override
public void onDestroy() {
super.onDestroy();
if (call != null) {
call.close();
}
closeLocalProfile();
}@
Override
protected void onResume() {
// TODO Auto-generated method stub
initializeManager(this);
super.onResume();
}
public void initializeManager(Context ctx) {
if (manager == null) {
Log.e("initialising ", "ini manager");
manager = SipManager.newInstance(ctx);
}
initializeLocalProfile(ctx);
}
public void initializeLocalProfile(final Context ctx) {
if (manager == null) {
updateStatus("Not Supporting.", ctx);
Log.e("return", "manager is null ");
return;
}
SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(ctx);
String username = prefs.getString("namePref", Prefs.getUserName(ctx));
String domain = prefs.getString("domainPref", "255.235.472");
String password = prefs.getString("passPref", Prefs.getUserPassword(ctx));
if (username.length() == 0 || domain.length() == 0 || password.length() == 0) {
return;
}
try {
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword(password);
me = builder.build();
Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(ctx, 0, intent, Intent.FILL_IN_DATA);
manager.open(me, pendingIntent, null);
if (!manager.isRegistered(me.getUriString())) {
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
Log.e("Sip restration", "Registering with SIP Server...");
updateStatus("Registering with SIP Server...", ctx);
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
Log.e("Sip restration", "Ready");
updateStatus("Ready", ctx);
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
Log.e("Registration Error Code ", SipErrorCode.toString(errorCode) + errorCode);
updateStatus(errorCode + " " + SipErrorCode.toString(errorCode), ctx);
}
});
} else {
Log.e("already register", "already register");
updateStatus("Ready", ctx);
}
} catch (ParseException pe) {
updateStatus("Connection Error.", ctx);
} catch (SipException se) {
updateStatus("Connection error.", ctx);
}
}
public Boolean closeLocalProfile() {
Log.e("Closing profile", "closing profile " + me.getUriString());
if (manager == null) {
return false;
}
try {
if (me != null) {
Log.e("Unregistering profile", "Un registering profile ");
manager.unregister(me, null);
manager.close(me.getUriString());
}
} catch (Exception ee) {
Log.d("WalkieTalkieActivity/onDestroy", "Failed to close local profile.", ee);
}
return false;
}
public void initiateCall(String number, final Context ctx, final View v) {
// updateStatus(sipAddress);
Log.d("Number", "" + number);
sipAddress = number;
Log.e("initiating call", "initiating call");
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {@
Override
public void onCallBusy(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("buzy", "buzy");
super.onCallBusy(call);
}@
Override
public void onCallHeld(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("held", "held");
super.onCallHeld(call);
}@
Override
public void onCalling(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("calling", "calling");
super.onCalling(call);
}@
Override
public void onChanged(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("changed", "changed");
super.onChanged(call);
}@
Override
public void onError(SipAudioCall call, int errorCode,
String errorMessage) {
// TODO Auto-generated method stub
Log.e("call error", "error" + SipErrorCode.toString(errorCode));
CallingScreen.fa.finish();
super.onError(call, errorCode, errorMessage);
}@
Override
public void onReadyToCall(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("ready to call", "ready to call ");
super.onReadyToCall(call);
}@
Override
public void onRinging(SipAudioCall call, SipProfile caller) {
// TODO Auto-generated method stub
Log.e("ringing", "ringing");
super.onRinging(call, caller);
}@
Override
public void onRingingBack(SipAudioCall call) {
// TODO Auto-generated method stub
Log.e("ringing back", "ringing back");
super.onRingingBack(call);
}@
Override
public void onCallEstablished(SipAudioCall call) {
Log.e("call established", "call established");
call.startAudio();
updateTime(true, ctx);
}@
Override
public void onCallEnded(SipAudioCall call) {
Log.e("call ended", "call ended");
updateTime(false, ctx);
CallingScreen.fa.finish();
}
};
Log.e("param 1 ", "" + me.getUriString());
call = manager.makeAudioCall(me.getUriString(), sipAddress + "@216.245.200.2:5060", listener, 30);
} catch (Exception e) {
e.printStackTrace();
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (me != null) {
try {
closeLocalProfile();
} catch (Exception ee) {
ee.printStackTrace();
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
public void updateStatus(final String status, final Context context) {
// Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
generateNotification(context, status);
}
});
}
public void updateTime(final Boolean status, final Context context) {
// Be a good citizen. Make sure UI changes fire on the UI thread.
this.runOnUiThread(new Runnable() {
public void run() {
if (status) {
CallingScreen.fa.ch = (Chronometer) CallingScreen.fa.findViewById(R.id.time);
CallingScreen.fa.ch.setTypeface(CallingScreen.normal);
CallingScreen.fa.calling_screen_text.setVisibility(View.GONE);
CallingScreen.fa.ch.setVisibility(View.VISIBLE);
CallingScreen.fa.ch.start();
} else {
CallingScreen.fa.ch.stop();
}
}
});
}
public void updateStatus(SipAudioCall call) {
String useName = call.getPeerProfile().getDisplayName();
if (useName == null) {
useName = call.getPeerProfile().getUserName();
}
// updateStatus(useName + "@" + call.getPeerProfile().getSipDomain());
}
public boolean onTouch(View v, MotionEvent event) {
if (call == null) {
return false;
} else if (event.getAction() == MotionEvent.ACTION_DOWN && call != null && call.isMuted()) {
call.toggleMute();
} else if (event.getAction() == MotionEvent.ACTION_UP && !call.isMuted()) {
call.toggleMute();
}
return false;
}
public void endcall() {
if (call != null) {
try {
call.endCall();
} catch (SipException se) {
Log.d("WalkieTalkieActivity/onOptionsItemSelected",
"Error ending call.", se);
}
call.close();
}
}
public void speaker(Boolean speak) {
if (call != null)
call.setSpeakerMode(speak);
}
public static void generateNotification(Context context, String message) {
int icon = R.drawable.ic_launcher;
long when = System.currentTimeMillis();
NotificationManager notificationManager = (NotificationManager)
context.getSystemService(Context.NOTIFICATION_SERVICE);
Notification notification = new Notification(icon, message, when);
String title = context.getString(R.string.app_name);
Intent notificationIntent = new Intent(context, Splash_screen.class);
// set intent so it does not start a new activity
notificationIntent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP |
Intent.FLAG_ACTIVITY_SINGLE_TOP);
PendingIntent intent =
PendingIntent.getActivity(context, 0, notificationIntent, 0);
notification.setLatestEventInfo(context, title, message, intent);
notificationManager.notify(0, notification);
}
public Boolean isRegistered() {
if (manager != null && me != null)
try {
return manager.isRegistered(me.getUriString());
} catch (SipException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return false;
}
}
LOGCAT1
12 - 23 14: 19: 10.930: E / Unregistering profile(32139): Un registering profile
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): Failed to close local profile.
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): android.net.sip.SipException: SipService.createSession() returns null
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at android.net.sip.SipManager.unregister(SipManager.java: 507)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at com.phone91.android.WalkieTalkieActivity.closeLocalProfile(WalkieTalkieActivity.java: 144)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at com.phone91.android.DialerActivity$1$2.onClick(DialerActivity.java: 79)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at com.android.internal.app.AlertController$ButtonHandler.handleMessage(AlertController.java: 174)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at android.os.Handler.dispatchMessage(Handler.java: 99)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at android.os.Looper.loop(Looper.java: 155)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at android.app.ActivityThread.main(ActivityThread.java: 5520)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at java.lang.reflect.Method.invokeNative(Native Method)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at java.lang.reflect.Method.invoke(Method.java: 511)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java: 1029)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java: 796)
12 - 23 14: 19: 10.990: D / WalkieTalkieActivity / onDestroy(32139): at dalvik.system.NativeStart.main(Native Method)
LOG CAT2 :
12-23 14:53:28.890: E/Unregistering profile(2001): Un registering profile
12-23 14:53:30.050: E/Registration Error Code(2001): DATA_CONNECTION_LOST-10
I've been checking SipDemo sample code, the one I assume you used as reference for your application, an also faced this error but with registration process.
After checking Android's source code (4.1), I saw this is a bug in stack's implementation. More in detail:
setRegistrationListener
), as network info hasn't been updated (no intent has been received), it returnsSipErrorCode.DATA_CONNECTION_LOST
, but, actually, session is finally properly registered.In you case, as you're providing
SipRegistrationListener
inunregister
method, this process fails. An ugly work around would be wait some time for intent to be received or don't provide the listener.You will also see that, if you replace
unregister
call bysetRegistrationLister
you will still receive same error so, something you can also try is create an upper management, this is, inonRegistrationDone
callback, you can set a flag to know if you can close or not the profile. Something like:and, when closing local profile:
Please note that I used an integer in
updateStatus
instead of a string and used a helper function,statusToString
to translate status codes to strings.As you probably noted, this would add an extra management layer that, initially, should already be in the stack but it's not. I'm not really sure this would fix all return errors (after checking source code I saw several possible errors), but should help.