Stuck with Android SIP for VoIP - Registration not running - android

I have an Elastix server, which is being used by my desktop calling app and Zoiper App perfectly for calling purposes. However my own app, which is using Android SIP is not working fine and I am unable to locate the real problem.
Whenever I call for profile registration, it gets failed and error message of REGISTRATION NOT RUNNING shows in the logs.
here is my code snippet:
public void InitializeProfile()
{
if (mSipManager == null)
{
return;
}
if (mSipProfile != null){
closeLocalProfile();
}
SipProfile.Builder builder = null;
try {
builder = new SipProfile.Builder(Username, Domain);
} catch (ParseException e) {
e.printStackTrace();
}
builder.setPassword(Password);
mSipProfile = builder.build();
Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
try {
mSipManager.open(mSipProfile, pendingIntent, null);
} catch (SipException e) {
Log.i("open", e.toString());
e.printStackTrace();
}
try {
mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
// updateStatus("Registering with SIP Server...");
Log.i("helloworld", "Registering with SIP Server...");
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
// updateStatus("Ready");
Log.i("helloworld", "Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) {
// updateStatus("Registration failed. Please check settings.");
Log.i("helloworld", "Registration failed. Please check settings."+ errorMessage+ " " + Integer.toString(errorCode));
}
});
} catch (SipException e) {
e.printStackTrace();
}
}

Related

QoS=1 with MqttAsyncClient subscription miss messages

I have foreground service acting as MQTT client. I'm using MqttAsyncClient mqttClient for this purpose.
I'm using QoS=1 on subscribe to topic:
mqttClient.subscribe("sensors/s1/", 1);
But in case my phone gets offline for some period of time it miss current period messages. Whole code is below.
Im my another application I'm using MqttAndroidClient mqttAndroidClient and in this case QoS=1 brings all missed messages.
mqttAndroidClient.subscribe(topic, 1, null, new IMqttActionListener() {...})
Why subscription with MqttAsyncClient with QoS=1 not retrieves all messages?
Whole code :
public class MqttGndService extends Service {
private String ip="ssl:myserver",port="8887";
private final IBinder mBinder = new LocalBinder();
private Handler mHandler;
private static final String TAG = "mqttservice";
private static boolean hasWifi = false;
private static boolean hasMmobile = false;
private ConnectivityManager mConnMan;
private volatile IMqttAsyncClient mqttClient;
private String uniqueID;
class MQTTBroadcastReceiver extends BroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
IMqttToken token;
boolean hasConnectivity = false;
boolean hasChanged = false;
NetworkInfo infos[] = mConnMan.getAllNetworkInfo();
for (int i = 0; i < infos.length; i++) {
if (infos[i].getTypeName().equalsIgnoreCase("MOBILE")) {
if ((infos[i].isConnected() != hasMmobile)) {
hasChanged = true;
hasMmobile = infos[i].isConnected();
}
Timber.tag(Utils.TIMBER_TAG).v( infos[i].getTypeName() + " is " + infos[i].isConnected());
} else if (infos[i].getTypeName().equalsIgnoreCase("WIFI")) {
if ((infos[i].isConnected() != hasWifi)) {
hasChanged = true;
hasWifi = infos[i].isConnected();
}
Timber.tag(Utils.TIMBER_TAG).v(infos[i].getTypeName() + " is " + infos[i].isConnected());
}
}
hasConnectivity = hasMmobile || hasWifi;
Timber.tag(Utils.TIMBER_TAG).v( "hasConn: " + hasConnectivity + " hasChange: " + hasChanged + " - " + (mqttClient == null || !mqttClient.isConnected()));
if (hasConnectivity && hasChanged && (mqttClient == null || !mqttClient.isConnected())) {
Timber.tag(Utils.TIMBER_TAG).v("Ready to connect");
doConnect();
Timber.tag(Utils.TIMBER_TAG).v("do connect done");
} else
{
Timber.tag(Utils.TIMBER_TAG).v("Connection not possible");
}
}
}
public class LocalBinder extends Binder {
public MqttGndService getService() {
// Return this instance of LocalService so clients can call public methods
return MqttGndService.this;
}
}
#Override
public IBinder onBind(Intent intent) {
return mBinder;
}
public void publish(String topic, MqttMessage message) {
SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(this);// we create a 'shared" memory where we will share our preferences for the limits and the values that we get from onsensorchanged
try {
mqttClient.publish(topic, message);
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void onCreate() {
Timber.tag(Utils.TIMBER_TAG).v("Creating MQTT service");
mHandler = new Handler();//for toasts
IntentFilter intentf = new IntentFilter();
setClientID();
intentf.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
registerReceiver(new MQTTBroadcastReceiver(), new IntentFilter(ConnectivityManager.CONNECTIVITY_ACTION));
mConnMan = (ConnectivityManager) getSystemService(CONNECTIVITY_SERVICE);
}
#Override
public void onConfigurationChanged(Configuration newConfig) {
Timber.tag(Utils.TIMBER_TAG).v( "onConfigurationChanged()");
android.os.Debug.waitForDebugger();
super.onConfigurationChanged(newConfig);
}
#Override
public void onDestroy() {
super.onDestroy();
Timber.tag(Utils.TIMBER_TAG).v("Service onDestroy");
}
private void setClientID() {
uniqueID = android.provider.Settings.Secure.getString(getContentResolver(), android.provider.Settings.Secure.ANDROID_ID);
Timber.tag(Utils.TIMBER_TAG).v("uniqueID=" + uniqueID);
}
private void doConnect() {
String broker = ip + ":" + port;
Timber.tag(Utils.TIMBER_TAG).v("mqtt_doConnect()");
IMqttToken token;
MqttConnectOptions options = new MqttConnectOptions();
options.setCleanSession(true);
options.setMaxInflight(100);//handle more messages!!so as not to disconnect
options.setAutomaticReconnect(true);
options.setConnectionTimeout(1000);
options.setKeepAliveInterval(300);
options.setUserName("cc50e3e91bf4");
options.setPassword("b".toCharArray());
try {
options.setSocketFactory(SocketFactoryMQ.getSocketFactory(this,""));
} catch (KeyStoreException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
} catch (CertificateException e) {
e.printStackTrace();
} catch (UnrecoverableKeyException e) {
e.printStackTrace();
}
Timber.tag(Utils.TIMBER_TAG).v("set socket factory done");
try {
mqttClient = new MqttAsyncClient(broker, uniqueID, new MemoryPersistence());
token = mqttClient.connect(options);
token.waitForCompletion(3500);
mqttClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(Throwable throwable) {
try {
mqttClient.disconnectForcibly();
mqttClient.connect();
} catch (MqttException e) {
e.printStackTrace();
}
}
#Override
public void messageArrived(String topic, MqttMessage msg) throws Exception {
Timber.tag(Utils.TIMBER_TAG).v("Message arrived from topic " + topic+ " msg: " + msg );
}
#Override
public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("published");
}
});
Timber.tag(Utils.TIMBER_TAG).v("will subscribe");
mqttClient.subscribe("sensors/s1/", 1);
} catch (MqttSecurityException e) {
Timber.tag(Utils.TIMBER_TAG).v("general connect exception");
e.printStackTrace();
} catch (MqttException e) {
switch (e.getReasonCode()) {
case MqttException.REASON_CODE_BROKER_UNAVAILABLE:
mHandler.post(new ToastRunnable("WE ARE OFFLINE BROKER_UNAVAILABLE!", 1500));
break;
case MqttException.REASON_CODE_CLIENT_TIMEOUT:
mHandler.post(new ToastRunnable("WE ARE OFFLINE CLIENT_TIMEOUT!", 1500));
break;
case MqttException.REASON_CODE_CONNECTION_LOST:
mHandler.post(new ToastRunnable("WE ARE OFFLINE CONNECTION_LOST!", 1500));
break;
case MqttException.REASON_CODE_SERVER_CONNECT_ERROR:
Timber.tag(Utils.TIMBER_TAG).v( "c " + e.getMessage());
e.printStackTrace();
break;
case MqttException.REASON_CODE_FAILED_AUTHENTICATION:
Intent i = new Intent("RAISEALLARM");
i.putExtra("ALLARM", e);
Timber.tag(Utils.TIMBER_TAG).v("b " + e.getMessage());
break;
default:
Timber.tag(Utils.TIMBER_TAG).v( "a " + e.getMessage() +" "+ e.toString());
}
}
mHandler.post(new ToastRunnable("WE ARE ONLINE!", 500));
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Timber.tag(Utils.TIMBER_TAG).v("onStartCommand");
String input = intent.getStringExtra(INTENT_ID);
Timber.tag(Utils.TIMBER_TAG).v("onStartCommand "+ input);
Intent notificationIntent = new Intent(this, MainActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this,
0, notificationIntent, 0);
Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)
.setContentTitle("Example Service")
.setContentText(input)
.setSmallIcon(R.drawable.ic_android)
.setContentIntent(pendingIntent)
.build();
startForeground(1, notification);
PowerManager powerManager = (PowerManager) getSystemService(POWER_SERVICE);
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyApp::MyWakelockTag");
wakeLock.acquire();
return START_STICKY;
}
}
You are setting cleansession to true (options.setCleanSession(true)); from the docs for setCleanSession:
If set to true the client and server will not maintain state across restarts of the client, the server or the connection. This means
Message delivery to the specified QOS cannot be maintained if the client, server or connection are restarted
The server will treat a subscription as non-durable
I think that the mqtt specs state this more clearly:
If CleanSession is set to 1, the Client and Server MUST discard any previous Session and start a new one. This Session lasts as long as the Network Connection. State data associated with this Session MUST NOT be reused in any subsequent Session
So when your application looses the connection the session is discarded and new messages will not be queued up for delivery. In addition unless you resubscribe when the connection comes back up you will not receive any additional messages.
However be aware that if you set cleansession to false then any new messages received while your client is offline will be queued for delivery (subject to the configuration of the broker) and this might not be what you want to happen if the client could be offline for a long time.

Android SIP Client Multiple Profiles

I'm making a SIP application and I need multiple profiles in it .
But I can only register 1 profile, once I register the second profile the registration will failed and will give me the SipErrorCode: -9 (IN_PROGRESS) .
Is there a way to register 2 Profiles at the same time ? Is it possible ?
This is how I register my SIP:
public SipManager manager = null;
public SipProfile me = null;
///....
if(manager == null) {
manager = SipManager.newInstance(getActivity());
}
///...
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(mainActivity, 0, intent, Intent.FILL_IN_DATA);
manager.open(me, pendingIntent, null);
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
Log.e("onRegisterR", "Registering SIP... " + localProfileUri);
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
Log.e("onRegisterS", "Registration Successful! " + localProfileUri);
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
Log.e("onRegisterF", errorMessage);
}
});
} catch (ParseException pe) {
Log.e("ParseException", pe.getMessage());
} catch (SipException se) {
Log.e("SipException", se.getMessage());
}
ps. I just implemented this code twice to make 2 Profiles

Android SipManager registration failed

I'm following Google's guidelines to create in app SIP calls as in https://developer.android.com/guide/topics/connectivity/sip.html
I created a test account on sip.zadarma.com which works with a SIP client I downloaded from the Google Play however when I try to register it in my app I get:
onRegistrationFailed errorCode = -4 errorMessage: registration not running
onRegistrationFailed errorCode = -9 errorMessage: 0
#Override
protected void onResume() {
super.onResume();
if (mNumberKeyedIn == null)
mNumberKeyedIn = "";
if (hasSIPPermissions()) {
initializeSIP();
} else {
requestSIPPermission();
}
}
#Override
public void onPause() {
super.onPause();
closeLocalProfile();
}
public void closeLocalProfile() {
if (mSipManager == null) {
return;
}
try {
if (mSipProfile != null) {
mSipManager.close(mSipProfile.getUriString());
if (mSipManager.isRegistered(mSipProfile.getProfileName()))
mSipManager.unregister(mSipProfile, null);
}
} catch (Exception e) {
Log.d(TAG, "Failed to close local profile.", e);
}
}
private void initializeSIP() {
if (callReceiver == null) {
IntentFilter filter = new IntentFilter();
filter.addAction("com.xxxx.android.apps.xxxx.activity.INCOMING_CALL");
callReceiver = new IncomingCallReceiver();
this.registerReceiver(callReceiver, filter);
}
try {
if (mSipManager == null) {
mSipManager = SipManager.newInstance(this);
if (!SipManager.isVoipSupported(this)) {
Toast.makeText(this, getString(R.string.sip_not_supported), Toast.LENGTH_SHORT).show();
return;
}
if (SipManager.isSipWifiOnly(this)) {
Toast.makeText(this, getString(R.string.sip_wifi_only), Toast.LENGTH_SHORT).show();
}
}
if (mSipProfile != null) {
closeLocalProfile();
}
SipProfile.Builder builder = new SipProfile.Builder(BuildConfig.SIP_USERNAME, BuildConfig.SIP_DOMAIN);
builder.setPassword(BuildConfig.SIP_PASSWORD);
//builder.setProtocol("TCP");
//builder.setAuthUserName(BuildConfig.SIP_USERNAME);
//builder.setPort(5060);
//builder.setOutboundProxy(BuildConfig.SIP_OUTBOUND_PROXY);
builder.setAutoRegistration(true);
mSipProfile = builder.build();
Intent intent = new Intent();
intent.setAction("com.xxxx.android.apps.xxxx.activity.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(this, 0, intent, Intent.FILL_IN_DATA);
mSipManager.open(mSipProfile, pendingIntent, null);
mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
updateStatus(getString(R.string.sip_registering), R.drawable.circle_orange, false);
Log.d(TAG, "onRegistering " + localProfileUri);
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
updateStatus(getString(R.string.sip_ready), R.drawable.circle_green, true);
Log.d(TAG, "onRegistrationDone " + localProfileUri + " expiryTime = " + expiryTime);
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
updateStatus(getString(R.string.sip_registration_failed), R.drawable.circle_red, false);
Log.e(TAG, "onRegistrationFailed " + localProfileUri + " errorCode = " + errorCode + " errorMessage: " + errorMessage);
}
});
} catch (ParseException e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.sip_not_configured), Toast.LENGTH_SHORT).show();
} catch (SipException e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.oops_something_went_wrong_short), Toast.LENGTH_SHORT).show();
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, getString(R.string.sip_not_supported), Toast.LENGTH_SHORT).show();
}
}
Any help will be much appreciated.
Following solutions should be tried before to test your Registration server before even looking into code for SipClient.
Try runnig any VoIP SoftPhone client to check your server, if its not working then debug that first i.e. PortNo/IP address issue.
If step one is working then try running Wireshark on server to track reply from incoming REGISTRATION Request from client.
Although from "Error logs " from your text means i.e. IP address is pingable but Registration Port No is not opened.
I don't think this is code issue. It must be your setup issue for sure.

I want to make a voip Call using my program

I'm currently developing an application for making VoIP/SIP calls, but I don't know why I cannot make a call to a number using my program. I have a valid SIP server_id, password and domain. Using that domain call can be made. Programming code is given below. Can anyone help me out?
public class CallActivity extends Activity {
public String sipAddress = "nizamcs#sip2sip.info";
public SipManager manager = null;
public SipProfile me = null;
public SipAudioCall call = null;
#Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.calling);
initializeManager();
}
public void initializeManager() {
if (manager == null) {
manager = SipManager.newInstance(this);
}
initializeLocalProfile();
}
public void initializeLocalProfile() {
if (manager == null) {
return;
}
if (me != null) {
closeLocalProfile();
}
String username = "my_username";
String domain = "my_domain";
String password = "my_password";
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 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);
manager.setRegistrationListener(me.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
Log.d("onRegistering", "Registering with SIP Server...");
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
Log.d("onRegistrationDone", "RegistrationDone..Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
Log.d("onRegistrationFailed", "RegistrationFailed");
}
});
} catch (ParseException pe) {
} catch (SipException se) {
}
initiateCall();
}
public void closeLocalProfile() {
if (manager == null) {
return;
}
try {
if (me != null) {
manager.close(me.getUriString());
}
} catch (Exception ee) {
Log.d("WalkieTalkieActivity/onDestroy",
"Failed to close local profile.", ee);
}
}
public void initiateCall() {
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
// updateStatus(call);
}
#Override
public void onCallEnded(SipAudioCall call) {
}
};
call = manager.makeAudioCall(me.getUriString(), sipAddress, listener, 300);
}
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();
}
}
}
}
Please check if your request is being send by using wireshark and see the response you get from the sip server. By doing it you can make sure if the request is actually being send or not.

SipDemo Outgoing Call

I've totally involved by SipDemo app. I am making Sip call and it is done. I can hear voice but other sip person is unable to hear my voice.
This is my Registration code:-
public void initializeLocalProfile() {
if (manager == null) {
return;
}
if (me != null) {
closeLocalProfile();
}
//sipcallid
// username and password should be same
// sipAddress = "101#217.xx.xxx.xxx";
String domain = sipAddress.substring(sipAddress.indexOf('#')+1);
String username = sipAddress.substring(0,sipAddress.indexOf('#'));
Toast.makeText(outcall.this, "domain = "+domain+" username "+username, Toast.LENGTH_LONG).show();
try {
SipProfile.Builder builder = new SipProfile.Builder(username, domain);
builder.setPassword("123456");
builder.setOutboundProxy(domain);
builder.setDisplayName(username);
builder.setAuthUserName(username);
//builder.setDisplayName(username);
// builder.setAutoRegistration(true);
// builder.setSendKeepAlive(true);
me = builder.build();
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");
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
updateStatus("Registration failed. Please check settings.");
}
});
} catch (SipException se) {
updateStatus("Connection error.");
} catch (ParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
This is my Initiate call:-
// sipcallid = "rahul22#sip2sip.info";
updateStatus(sipcallid);
try {
SipAudioCall.Listener listener = new SipAudioCall.Listener() {
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
//call.setSpeakerMode(true);
call.toggleMute();
updateStatus1("on call established");
}
#Override
public void onCallEnded(SipAudioCall call) {
updateStatus1("on call end");
finish();
}
};
call = manager.makeAudioCall(me.getUriString(), sipcallid, listener, 30);
updateStatus1(""+call.getState());
}
catch (Exception e) {
Toast.makeText(outcall.this, "Error when trying to close manager"+ e.getMessage(), Toast.LENGTH_LONG).show();
if (me != null) {
try {
manager.close(me.getUriString());
} catch (Exception ee) {
Toast.makeText(outcall.this, "ee"+ e.getMessage(), Toast.LENGTH_LONG).show();
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
Please Except. I can hear the voice of other person but other person can't hear my voice.
please help me!. Thank you for your timing.
It raise when your IP adress is NAT address usually. Android not support NAT by default. For supporting with NAT you will use other external libraries such as CSipSimple.
I see that you call call.toggleMute()
Could it be that you are muting the microphone? The SipDemo app has a button which unmutes the microphone.
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;
}
Maybe you just mute the microphone when you initiate the call but never unmute?

Categories

Resources