I've been coding a SIP client using the Android SDK's native SIP libs.
For some reason I cannot get my account to register with the server.
Here are the testing grounds:
Linux Mint 17 XFCE running a Kamailio Server(MySQL and TLS enabled).
Linux Mint 17 Cinnamon running Android Studio (0.8.6).
Asus Google Nexus 7 (2nd gen).
All of the above are on 192.168.1.xxx
The server and account info has been tested with a working SipClient (ZoIPer). The port 5060 has been tested with a telnet command from the coding machine to the server. The client I'm building has also been tested with a third-party SIP service on a distant server (with identical results). Is there any idea how to make it works?
MainActivity
public class MainActivity extends Activity {
public CommsController cc;
public IncomingCallReceiver callReceiver;
public Context ctx = this;
Button callButton;
EditText phoneTextBox;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
cc = new CommsController();
cc.createManager(this);
cc.createProfile("linasAndroid","192.168.1.140","android001");
callReceiver = new IncomingCallReceiver();
IntentFilter filter = new IntentFilter();
filter.addAction("util.Controller.IncomingCallReceiver");
this.registerReceiver(callReceiver, filter);
cc.openProfile(this);
try {
System.out.println("+++ IS API SUPPORTED: " + cc.getManager().isApiSupported(this));
System.out.println("+++ IS VOIP SUPORTED: " + cc.getManager().isVoipSupported(this));
System.out.println("+++ MANAGER INSTANCE: " + cc.getManager().toString());
boolean isOpened = cc.getManager().isOpened(cc.getMe().getUriString());
System.out.println("+++ IS OPENED: "+isOpened);
if(isOpened){
cc.getManager().register(cc.getMe(), 30000, cc.getSrl());
cc.createRegistrationListener();
}
}catch(SipException sipex){
System.out.println(sipex.getCause()+", "+ sipex.getMessage());
//sipex.printStackTrace();
}
callButton = (Button) findViewById(R.id.callButton);
phoneTextBox = (EditText) findViewById(R.id.phoneTextBox);
callButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
cc.makeCall("sip:"+phoneTextBox.getText()+"#192.168.1.140");
}
});
}
#Override
protected void onDestroy() {
super.onDestroy();
this.unregisterReceiver(callReceiver);
}
public Context getContext(){return ctx;}
public CommsController getCc() {
return cc;
}
CommsController
public class CommsController {
public String sipAddress = null;
public SipManager manager = null;
public SipProfile me = null;
public SipAudioCall call = null;
public Context ctx;
private PendingIntent pendingIntent;
public SipRegistrationListener srl;
private static final int CALL_ADDRESS = 1;
private static final int SET_AUTH_INFO = 2;
private static final int UPDATE_SETTINGS_DIALOG = 3;
private static final int HANG_UP = 4;
SipAudioCall.Listener listener = new SipAudioCall.Listener(){
#Override
public void onCallEstablished(SipAudioCall call) {
call.startAudio();
call.setSpeakerMode(true);
call.toggleMute();
}
#Override
public void onCallEnded(SipAudioCall call) {
// Do something.
}
};
public void createManager(Context context) {
if (manager == null) {
manager = SipManager.newInstance(context);
}
}
public boolean createProfile(String uname, String domain, String pass){
try {
SipProfile.Builder builder = new SipProfile.Builder(uname, domain);
builder.setPassword(pass);
builder.setProtocol("TCP");
builder.setPort(5060);
me = builder.build();
setMe(me);
System.out.println("+++ User Profile = CREATED");
return true;
} catch (ParseException e) {
e.printStackTrace();
System.out.println("+++ User Profile = FAILED");
return false;
}
}
public void openProfile(Context context){
try {
System.out.println("+++ ATTEMPTING TO OPEN PROFILE: " + me.getUriString());
Intent intent = new Intent();
intent.setAction("util.Controller.IncomingCallReceiver");
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, Intent.FILL_IN_DATA);
manager.open(getMe(), pendingIntent, null);
System.out.println("+++ IS OPEN IN CC: " +manager.isOpened(getMe().getUriString()));
} catch (SipException e) {
e.printStackTrace();
System.out.println("+++ Profile Registration = FAILED");
}
}
public void createRegistrationListener(){
System.out.println("+++ CREATING REG LISTENER...");
srl = new SipRegistrationListener() {
#Override
public void onRegistering(String localProfileUri) {
System.out.println("+++ REGISTERING...");
}
#Override
public void onRegistrationDone(String localProfileUri, long expiryTime) {
System.out.println("+++ READY");
}
#Override
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage) {
System.out.println("+++ REGISTRATION FAILED. CHECK SETTINGS. ERROR: "+ errorCode + " MESSAGE: " +errorMessage);
}
};
}
public SipRegistrationListener getSrl(){
return srl;
}
public void closeProfile(SipProfile toClose){
if(manager==null){
return;
}
try {
if (manager != null) {
manager.close(toClose.getUriString());
System.out.println("PROFILE CLOSED: " +toClose.getUriString());
}
} catch (Exception ee) {
ee.printStackTrace();
System.out.println("FAILED TO CLOSE LOCAL PROFILE: "+ toClose.toString());
}
}
public void logOut(){
try {
System.out.println("+++ DEREGISTERING...");
manager.close(me.getUriString());
}catch(SipException se){
System.out.println("+++ DEREGISTRATION FAILED");
se.printStackTrace();
}
}
public void makeCall(String toCall){
try {
call = manager.makeAudioCall(me.getUriString(), toCall, listener, 30);
} catch (SipException e) {
e.printStackTrace();
}
}
//Getters and setters...
Output (LogCat)
09-09 16:46:53.709 22783-22783/com.inlusion.inlusip I/Adreno-EGL﹕ <qeglDrvAPI_eglInitialize:320>: EGL 1.4 QUALCOMM Build: I0404c4692afb8623f95c43aeb6d5e13ed4b30ddbDate: 11/06/13
09-09 16:46:53.739 22783-22783/com.inlusion.inlusip D/OpenGLRenderer﹕ Enabling debug mode 0
09-09 16:46:55.841 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ User Profile = CREATED
09-09 16:46:55.841 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ ATTEMPTING TO OPEN PROFILE: sip:linasAndroid#192.168.1.140;transport=tcp
09-09 16:46:55.921 22783-22783/com.inlusion.inlusip D/dalvikvm﹕ GC_FOR_ALLOC freed 316K, 4% free 9182K/9532K, paused 19ms, total 19ms
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS OPEN IN CC: false
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS API SUPPORTED: true
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS VOIP SUPORTED: true
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ MANAGER INSTANCE: android.net.sip.SipManager#4256de78
09-09 16:46:55.941 22783-22783/com.inlusion.inlusip I/System.out﹕ +++ IS OPENED: false
EDIT:
After messing around with pjsip, mjsip and jain-sip, I desparately made one last attempt to rewrite this using the SDKs sip stack, in a more structured manner, separating the methods into classes that handle talking to the registrar, handling a call etc., you know- standard MVC layout.
After two weeks of repackaging third-party libraries and trying to figure out the NDK...
This bastard worked. Goes to show - structure your code right!
EDIT 2:
The issue is back after removing the app from the device and running it again. Once more- no idea what's causing it. Had gotten to the point where I could register, unregister and make two way audio calls until it started happening again.
EDIT 3:
It seems the problem goes away when the device is rebooted. Starting to think it's either an unclosed socket or a previously opened profile. Any suggestions?
EDIT 4:
Bug also occurs when another VoIP SIP application (with the pjsip OR mjsip stack) is present and connected to the server with the same account credentials.
Related
I've a Service to manage my MQTT Client connection, the MQTT works fine, but the problem is when I restart Broker Server, the Android client not reconnect. A exception is triggered on onConnectionLost() callback.
Notes
I'm using Moquette Broker at same computer -> Moquette
I've two Android clients app, a using Service (the problematic) and other working on a Thread, without Service (this works fine, reconnect is ok).
I can't run the Android Client MQTT lib, because this I'm using the Eclipse Paho MQTT.
Yes, I make setAutomaticReconnect(true);
Problem
The Android app that use Service, to works forever, not reconnect to MQTT Broker.
Code
MQTTService.java
public class MQTTService extends Service implements MqttCallbackExtended {
boolean running;
private static final String TAG = "MQTTService";
public static final String ACTION_MQTT_CONNECTED = "ACTION_MQTT_CONNECTED";
public static final String ACTION_MQTT_DISCONNECTED = "ACTION_MQTT_DISCONNECTED";
public static final String ACTION_DATA_ARRIVED = "ACTION_DATA_ARRIVED";
// MQTT
MqttClient mqttClient;
final String serverURI = "tcp://"+ServidorServices.IP+":1883";
final String clientId = "Responsavel";
String topicoId;
Thread mqttStartThread;
public boolean subscribe(String topic) {
try {
Log.i(TAG,"Subscripe: " + topic);
mqttClient.subscribe(topic);
mqttClient.subscribe("LOCATION_REAL");
return true;
} catch (Exception e) {
e.printStackTrace();
}
return false;
}
// Life Cycle
#Override
public IBinder onBind(Intent intent) {
Log.d(TAG,"onBind()");
return null;
}
#Override
public void onCreate() {
Log.d(TAG,"onCreate()");
running = true;
topicoId = getSharedPreferences("myprefs",MODE_PRIVATE).getString("tag_id_aluno","0");
mqttStartThread = new MQTTStartThread(this);
if(topicoId.equals("0")) {
Log.i(TAG,"Error to subscribe");
return;
}
mqttStartThread.start();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG,"onStartCommand()");
return super.onStartCommand(intent, flags, startId);
}
class MQTTStartThread extends Thread {
MqttCallbackExtended mqttCallbackExtended;
public MQTTStartThread(MqttCallbackExtended callbackExtended) {
this.mqttCallbackExtended = callbackExtended;
}
#Override
public void run() {
try {
mqttClient = new MqttClient(serverURI,clientId,new MemoryPersistence());
MqttConnectOptions options = new MqttConnectOptions();
options.setAutomaticReconnect(true);
options.setCleanSession(true);
mqttClient.setCallback(mqttCallbackExtended);
mqttClient.connect();
} catch (Exception e) {
Log.i(TAG,"Exception MQTT CONNECT: " + e.getMessage());
e.printStackTrace();
}
}
}
#Override
public void onDestroy() {
Log.d(TAG,"onDestroy()");
running = false;
if (mqttClient != null) {
try {
if (mqttClient.isConnected()) mqttClient.disconnect();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Override
public boolean onUnbind(Intent intent) {
Log.i(TAG,"onUnbind()");
return super.onUnbind(intent);
}
// Callbacks MQTT
#Override
public void connectComplete(boolean reconnect, String serverURI) {
Log.i(TAG,"connectComplete()");
if (topicoId == null) {
Log.i(TAG,"Erro ao ler ID da Tag");
return;
}
sendBroadcast(new Intent(ACTION_MQTT_CONNECTED));
subscribe(topicoId);
}
#Override
public void connectionLost(Throwable cause) {
Log.i(TAG,"connectionLost(): " + cause.getMessage());
cause.printStackTrace();
sendBroadcast(new Intent(ACTION_MQTT_DISCONNECTED));
}
#Override
public void messageArrived(String topic, MqttMessage message) throws Exception {
Log.i(TAG,"messageArrived() topic: " + topic);
if (topic.equals("LOCATION_REAL")) {
Log.i(TAG,"Data: " + new String(message.getPayload()));
} else {
Context context = MQTTService.this;
String data = new String(message.getPayload());
Intent intent = new Intent(context,MapsActivity.class);
intent.putExtra("location",data);
LatLng latLng = new LatLng(Double.valueOf(data.split("_")[0]),Double.valueOf(data.split("_")[1]));
String lugar = Utils.getAddressFromLatLng(latLng,getApplicationContext());
NotificationUtil.create(context,intent,"Embarque",lugar,1);
if (data.split("_").length < 3) {
return;
}
double latitude = Double.valueOf(data.split("_")[0]);
double longitude = Double.valueOf(data.split("_")[1]);
String horario = data.split(" ")[2];
Intent iMqttBroadcast = new Intent(ACTION_DATA_ARRIVED);
iMqttBroadcast.putExtra("topico",String.valueOf(topic));
iMqttBroadcast.putExtra("latitude",latitude);
iMqttBroadcast.putExtra("longitude",longitude);
iMqttBroadcast.putExtra("evento","Embarcou");
iMqttBroadcast.putExtra("horario",horario);
sendBroadcast(iMqttBroadcast);
}
}
#Override
public void deliveryComplete(IMqttDeliveryToken token) {
Log.i(TAG,"deliveryComplete()");
}
}
Exception Stacktrace
I/MQTTService: connectionLost(): Connection lost
W/System.err: Connection lost (32109) - java.io.EOFException
W/System.err: at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:146)
W/System.err: at java.lang.Thread.run(Thread.java:818)
W/System.err: Caused by: java.io.EOFException
W/System.err: at java.io.DataInputStream.readByte(DataInputStream.java:77)
W/System.err: at org.eclipse.paho.client.mqttv3.internal.wire.MqttInputStream.readMqttWireMessage(MqttInputStream.java:65)
W/System.err: at org.eclipse.paho.client.mqttv3.internal.CommsReceiver.run(CommsReceiver.java:107)
W/System.err: ... 1 more
I think you forgot to include MqttConnectOptions with MqttClient object.
Please try like following
mqttClient.connect(options);
instead of
mqttClient.connect();
Hope it may help to resolve your re-connect issue.
As method description says.
options.setAutomaticReconnect(true);
The client will attempt to reconnect to the server. It will initially wait 1 second before it attempts to reconnect, for every failed reconnect attempt, the delay will doubleuntil it is at 2 minutes at which point the delay will stay at 2 minutes.
Another option would be you could manage retry interval in case of connection lost events.
First time trying to do IP Discovery in Android. I used the http://developer.android.com/training/connect-devices-wirelessly/nsd.html#discover and wrote the code. I am not registering the device, just Discovering Services in the network. When I run the project in emulator or device the onDiscoveryStarted() gets called, but the onServiceFound() is never called. Please find my Code below. Any input is much appreciated. Thanks!
public class MainActivity extends AppCompatActivity {
private Button discoverButton;
Context mContext;
NsdManager mNsdManager;
NsdManager.ResolveListener mResolveListener;
NsdManager.DiscoveryListener mDiscoveryListener;
NsdManager.RegistrationListener mRegistrationListener;
public static final String SERVICE_TYPE = "_http._tcp.";
public static final String TAG = "MyApp_MAIN_CLIENT";
public String mServiceName = "MyApp";
/*
* public static final String SERVICE_TYPE = "_http._tcp.";
public static final String TAG = "NsdHelper";
public String mServiceName = "NsdChat";
* */
NsdServiceInfo mService;
private Handler mUpdateHandler;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mNsdManager = (NsdManager) this.getSystemService(Context.NSD_SERVICE);
discoverButton = (Button) findViewById(R.id.netButton);
discoverButton.setOnClickListener(new View.OnClickListener() {
public void onClick(android.view.View v) {
initializeDiscoveryListener();
initializeResolveListener();
discoverServices();
}
});
}
public void discoverServices() {
mNsdManager.discoverServices(
SERVICE_TYPE, NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
}
public void initializeDiscoveryListener() {
// Instantiate a new DiscoveryListener
mDiscoveryListener = new NsdManager.DiscoveryListener() {
// Called as soon as service discovery begins.
#Override
public void onDiscoveryStarted(String regType) {
Log.d(TAG, "Service discovery started");
}
#Override
public void onServiceFound(NsdServiceInfo service) {
// A service was found! Do something with it.
Log.d(TAG, "Service discovery success" + service);
if (!service.getServiceType().equals(SERVICE_TYPE)) {
// Service type is the string containing the protocol and
// transport layer for this service.
Log.d(TAG, "Unknown Service Type: " + service.getServiceType());
} /*else if (service.getServiceName().equals(mServiceName)) {
// The name of the service tells the user what they'd be
// connecting to. It could be "Bob's Chat App".
Log.d(TAG, "Same machine: " + mServiceName);
}
//else if (service.getServiceName().contains("NsdChat")){*/
else{
mNsdManager.resolveService(service, mResolveListener);
}
}
#Override
public void onServiceLost(NsdServiceInfo service) {
// When the network service is no longer available.
// Internal bookkeeping code goes here.
Log.e(TAG, "service lost" + service);
}
#Override
public void onDiscoveryStopped(String serviceType) {
Log.i(TAG, "Discovery stopped: " + serviceType);
}
#Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
#Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
Log.e(TAG, "Discovery failed: Error code:" + errorCode);
mNsdManager.stopServiceDiscovery(this);
}
};
}// end of initializeListener()
public void initializeResolveListener() {
mResolveListener = new NsdManager.ResolveListener() {
#Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
Log.e(TAG, "Resolve failed" + errorCode);
}
#Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
Log.e(TAG, "Resolve Succeeded. " + serviceInfo);
if (serviceInfo.getServiceName().equals(mServiceName)) {
Log.d(TAG, "Same IP.");
return;
}
mService = serviceInfo;
int port = mService.getPort();
InetAddress host = mService.getHost();
Log.d(TAG,host.toString());
}
};
}//end of initializeResolveListener
#Override
protected void onPause() {
super.onPause();
stopDiscovery();
tearDown();
}
#Override
protected void onResume() {
super.onResume();
discoverServices();
}
#Override
protected void onDestroy() {
tearDown();
super.onDestroy();
}
public void stopDiscovery() {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
}
public void tearDown() {
mNsdManager.unregisterService(mRegistrationListener);
}
}
From NdsManager documentation page:
The API currently supports DNS based service discovery and discovery
is currently limited to a local network over Multicast DNS.
From this Local networking limitations emulator docs page:
Currently, the emulator does not support IGMP or multicast.
Hope this will help you
Probably due to the age of this post, I hope you already found a solution.
If not, my experience is that the Android Emulator (API level 25) does not provide a full network stack and the service discovery through NSD isn't working.
I switched to debugging on a real device (like an Android TV or tablet) and then my whole NSD/Bonjour-like setup was working. The methods of the DiscoveryListener and the ResolveListener were called and an IP and port (in my case) were retrieved.
After some hours working with Android NSD, I discovered that this library does not work with routers that don't support Multicast. While the other answers may are correct, this could also be the cause of your problem. Possible solutions: enable Multicast on your router if possible, or use another network library.
The Network Service Discovery Manager class provides the API to discover services on a network.
This will work when your device is connected to the same WIFI network as that of the device providing the service.
Hope this helps!!
Happy Coding!!
I'm working on an Android Wi-Fi P2p project (also called WiFi direct).
This is how I try to create the group:
public class WiFiDirectBroadcastReceiver extends BroadcastReceiver {
private WifiP2pManager mManager;
private Channel mChannel;
private MainActivity mActivity;
public WiFiDirectBroadcastReceiver(WifiP2pManager p2pManager,
Channel channel, MainActivity mainActivity) {
super();
this.mManager = p2pManager;
this.mChannel = channel;
this.mActivity = mainActivity;
}
#Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (WifiP2pManager.WIFI_P2P_STATE_CHANGED_ACTION.equals(action)) {
String state = MainActivity.wifiP2PStateMap.get(intent.getIntExtra(WifiP2pManager.EXTRA_WIFI_STATE, -1));
if (state.equalsIgnoreCase("ENABLED")) {
Log.d(MainActivity.TAG, "P2P state changed to ENABLED ");
mManager.createGroup(mChannel, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(MainActivity.TAG, "Group created ");
}
#Override
public void onFailure(int reason) {
Log.d(MainActivity.TAG, "Failed to create Group " + MainActivity.failureMap.get(reason));
}
});
}
}else if (WifiP2pManager.WIFI_P2P_PEERS_CHANGED_ACTION.equals(action)){
//STUB
}else if (WifiP2pManager.WIFI_P2P_DISCOVERY_CHANGED_ACTION.equals(action)){
//STUB
}else if (WifiP2pManager.WIFI_P2P_CONNECTION_CHANGED_ACTION.equals(action)) {
//STUB
}else if (WifiP2pManager.WIFI_P2P_THIS_DEVICE_CHANGED_ACTION.equals(action)) {
//STUB
}
}
}
When I scan the available wifi groups using wifi-analyzer I see that my group was created on channel 1, and it is always on channel 1.
Since this channel might be over crowded with other Access points I want to use a different channel.
The problem is that Android's API does not have a visible method to change the channel.
Here I found these questions: Q1, Q2, but they suggest rooting the device which is not an option for me.
When I looked into Android's sources I found that there is a hidden method:
/** #hide */
public void setWifiP2pChannels(Channel c, int lc, int oc, ActionListener listener) {
checkChannel(c);
Bundle p2pChannels = new Bundle();
p2pChannels.putInt("lc", lc);
p2pChannels.putInt("oc", oc);
c.mAsyncChannel.sendMessage(SET_CHANNEL, 0, c.putListener(listener), p2pChannels);
}
Using reflection I tried the following:
Method setWifiP2pChannels = p2pManager.getClass().getMethod("setWifiP2pChannels", WifiP2pManager.Channel.class, int.class, int.class, WifiP2pManager.ActionListener.class);
setWifiP2pChannels.invoke(p2pManager, channel, 0, channel_to_set, new WifiP2pManager.ActionListener() {
#Override
public void onSuccess() {
Log.d(MainActivity.TAG, "Changed channel (" + channel_to_set + ") succeeded");
}
#Override
public void onFailure(int reason) {
Log.d(MainActivity.TAG, "Changed channel (" + channel_to_set + ") failed");
}
});
When channel_to_set was 0 or 1 the actual channel did not change. When channel_to_set to something higher, creating a group returned an error.
Any idea how to solve this?
Thanks
How to implement SIP protocol in Android ?
there is any SDK or library available to implement it easily into Android?
Here is a third party Library with sample code. You can use this, I have used it and it works fine.
Android 2.3 or higher provides API for SIP.
Refer this link for SIP in Android
also you can see DEMO project for SIP from Sample
update:
Android SDK Samples on github.
SipDemo1, SipDemo2
Search for SipDemo project in samples for android 4.0.3 SDK version(API level -15)
I have been investigated this sort of problem for a long time and found out that SipManager and SipProfile are unfortunatelly poor and extremelly buggy.
So I found a Linphone library. There is a link for their wiki. I implemented it in my project using maven:
repositories {
...
maven { "https://linphone.org/maven_repository/"}
}
Also there is a sample of using it on gitlab: link here, it's pretty fresh, for now :)
If the link would crash, I just copy/paste the most important part of how to use linphone's core:
public class LinphoneService extends Service {
private static final String START_LINPHONE_LOGS = " ==== Device information dump ====";
// Keep a static reference to the Service so we can access it from anywhere in the app
private static LinphoneService sInstance;
private Handler mHandler;
private Timer mTimer;
private Core mCore;
private CoreListenerStub mCoreListener;
public static boolean isReady() {
return sInstance != null;
}
public static LinphoneService getInstance() {
return sInstance;
}
public static Core getCore() {
return sInstance.mCore;
}
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onCreate() {
super.onCreate();
// The first call to liblinphone SDK MUST BE to a Factory method
// So let's enable the library debug logs & log collection
String basePath = getFilesDir().getAbsolutePath();
Factory.instance().setLogCollectionPath(basePath);
Factory.instance().enableLogCollection(LogCollectionState.Enabled);
Factory.instance().setDebugMode(true, getString(R.string.app_name));
// Dump some useful information about the device we're running on
Log.i(START_LINPHONE_LOGS);
dumpDeviceInformation();
dumpInstalledLinphoneInformation();
mHandler = new Handler();
// This will be our main Core listener, it will change activities depending on events
mCoreListener = new CoreListenerStub() {
#Override
public void onCallStateChanged(Core core, Call call, Call.State state, String message) {
Toast.makeText(LinphoneService.this, message, Toast.LENGTH_SHORT).show();
if (state == Call.State.IncomingReceived) {
Toast.makeText(LinphoneService.this, "Incoming call received, answering it automatically", Toast.LENGTH_LONG).show();
// For this sample we will automatically answer incoming calls
CallParams params = getCore().createCallParams(call);
params.enableVideo(true);
call.acceptWithParams(params);
} else if (state == Call.State.Connected) {
// This stats means the call has been established, let's start the call activity
Intent intent = new Intent(LinphoneService.this, CallActivity.class);
// As it is the Service that is starting the activity, we have to give this flag
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
}
}
};
try {
// Let's copy some RAW resources to the device
// The default config file must only be installed once (the first time)
copyIfNotExist(R.raw.linphonerc_default, basePath + "/.linphonerc");
// The factory config is used to override any other setting, let's copy it each time
copyFromPackage(R.raw.linphonerc_factory, "linphonerc");
} catch (IOException ioe) {
Log.e(ioe);
}
// Create the Core and add our listener
mCore = Factory.instance()
.createCore(basePath + "/.linphonerc", basePath + "/linphonerc", this);
mCore.addListener(mCoreListener);
// Core is ready to be configured
configureCore();
}
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
// If our Service is already running, no need to continue
if (sInstance != null) {
return START_STICKY;
}
// Our Service has been started, we can keep our reference on it
// From now one the Launcher will be able to call onServiceReady()
sInstance = this;
// Core must be started after being created and configured
mCore.start();
// We also MUST call the iterate() method of the Core on a regular basis
TimerTask lTask =
new TimerTask() {
#Override
public void run() {
mHandler.post(
new Runnable() {
#Override
public void run() {
if (mCore != null) {
mCore.iterate();
}
}
});
}
};
mTimer = new Timer("Linphone scheduler");
mTimer.schedule(lTask, 0, 20);
return START_STICKY;
}
#Override
public void onDestroy() {
mCore.removeListener(mCoreListener);
mTimer.cancel();
mCore.stop();
// A stopped Core can be started again
// To ensure resources are freed, we must ensure it will be garbage collected
mCore = null;
// Don't forget to free the singleton as well
sInstance = null;
super.onDestroy();
}
#Override
public void onTaskRemoved(Intent rootIntent) {
// For this sample we will kill the Service at the same time we kill the app
stopSelf();
super.onTaskRemoved(rootIntent);
}
private void configureCore() {
// We will create a directory for user signed certificates if needed
String basePath = getFilesDir().getAbsolutePath();
String userCerts = basePath + "/user-certs";
File f = new File(userCerts);
if (!f.exists()) {
if (!f.mkdir()) {
Log.e(userCerts + " can't be created.");
}
}
mCore.setUserCertificatesPath(userCerts);
}
private void dumpDeviceInformation() {
StringBuilder sb = new StringBuilder();
sb.append("DEVICE=").append(Build.DEVICE).append("\n");
sb.append("MODEL=").append(Build.MODEL).append("\n");
sb.append("MANUFACTURER=").append(Build.MANUFACTURER).append("\n");
sb.append("SDK=").append(Build.VERSION.SDK_INT).append("\n");
sb.append("Supported ABIs=");
for (String abi : Version.getCpuAbis()) {
sb.append(abi).append(", ");
}
sb.append("\n");
Log.i(sb.toString());
}
private void dumpInstalledLinphoneInformation() {
PackageInfo info = null;
try {
info = getPackageManager().getPackageInfo(getPackageName(), 0);
} catch (PackageManager.NameNotFoundException nnfe) {
Log.e(nnfe);
}
if (info != null) {
Log.i(
"[Service] Linphone version is ",
info.versionName + " (" + info.versionCode + ")");
} else {
Log.i("[Service] Linphone version is unknown");
}
}
private void copyIfNotExist(int ressourceId, String target) throws IOException {
File lFileToCopy = new File(target);
if (!lFileToCopy.exists()) {
copyFromPackage(ressourceId, lFileToCopy.getName());
}
}
private void copyFromPackage(int ressourceId, String target) throws IOException {
FileOutputStream lOutputStream = openFileOutput(target, 0);
InputStream lInputStream = getResources().openRawResource(ressourceId);
int readByte;
byte[] buff = new byte[8048];
while ((readByte = lInputStream.read(buff)) != -1) {
lOutputStream.write(buff, 0, readByte);
}
lOutputStream.flush();
lOutputStream.close();
lInputStream.close();
}
}
I hope, that will help somebody, because I spend a lot of time trying to find it!
I used by this library:
https://www.mizu-voip.com/Software/SIPSDK/AndroidSIPSDK.aspx
it is very easy.
also i add button for answer the call:
mysipclient.Accept(mysipclient.GetLine());
I'm trying to establish a bluetooth connexion between a Samsung Galaxy S3 running with Android 4.0.3 and a RN 42 Bluetooth Chip, here is the model :
I used lot's of different codes for setting up a bluetooth serial communication, and all of them are working very well on the HTC Wildfire i was using before. But now that i'm using the galaxy s3 phone, it's impossible to establish the connexion. Here is the code i'm using, i found it here :
I put the permissions in the android manifest.
First, my Bluetooth Interface :
public class BtInterface {
private BluetoothDevice device = null;
private BluetoothSocket socket = null;
private InputStream receiveStream = null;
private OutputStream sendStream = null;
private ReceiverThread receiverThread;
Handler handler;
public BtInterface(Handler hstatus, Handler h) {
Set<BluetoothDevice> setpairedDevices = BluetoothAdapter.getDefaultAdapter().getBondedDevices();
BluetoothDevice[] pairedDevices = (BluetoothDevice[]) setpairedDevices.toArray(new BluetoothDevice[setpairedDevices.size()]);
for(int i=0;i<pairedDevices.length;i++) {
if(pairedDevices[i].getName().contains("MyBluetoothChip")) {
device = pairedDevices[i];
try {
socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB"));
receiveStream = socket.getInputStream();
sendStream = socket.getOutputStream();
} catch (IOException e) {
e.printStackTrace();
}
break;
}
}
handler = hstatus;
receiverThread = new ReceiverThread(h);
}
public void sendData(String data) {
sendData(data, false);
}
public void sendData(String data, boolean deleteScheduledData) {
try {
sendStream.write(data.getBytes());
sendStream.flush();
} catch (IOException e) {
e.printStackTrace();
}
}
public void connect() {
new Thread() {
#Override public void run() {
try {
socket.connect();
Message msg = handler.obtainMessage();
msg.arg1 = 1;
handler.sendMessage(msg);
receiverThread.start();
} catch (IOException e) {
Log.v("N", "Connection Failed : "+e.getMessage());
e.printStackTrace();
}
}
}.start();
}
public void close() {
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public BluetoothDevice getDevice() {
return device;
}
private class ReceiverThread extends Thread {
Handler handler;
ReceiverThread(Handler h) {
handler = h;
}
#Override public void run() {
while(true) {
try {
if(receiveStream.available() > 0) {
byte buffer[] = new byte[100];
int k = receiveStream.read(buffer, 0, 100);
if(k > 0) {
byte rawdata[] = new byte[k];
for(int i=0;i<k;i++)
rawdata[i] = buffer[i];
String data = new String(rawdata);
Message msg = handler.obtainMessage();
Bundle b = new Bundle();
b.putString("receivedData", data);
msg.setData(b);
handler.sendMessage(msg);
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
Then, my main activity, with just a button to connect and a chat :
public class MonApp extends Activity implements OnClickListener {
private TextView logview;
private EditText sendtext;
private Button connect, send;
private BtInterface bt = null;
private long lastTime = 0;
final Handler handler = new Handler() {
public void handleMessage(Message msg) {
String data = msg.getData().getString("receivedData");
long t = System.currentTimeMillis();
if(t-lastTime > 100) {// Pour Èviter que les messages soit coupÈs
logview.append("\n");
lastTime = System.currentTimeMillis();
}
logview.append(data);
}
};
final Handler handlerStatus = new Handler() {
public void handleMessage(Message msg) {
int co = msg.arg1;
if(co == 1) {
logview.append("Connected\n");
} else if(co == 2) {
logview.append("Disconnected\n");
}
}
};
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
bt = new BtInterface(handlerStatus, handler);
logview = (TextView)findViewById(R.id.logview);
sendtext = (EditText)findViewById(R.id.sendtxt);
connect = (Button)findViewById(R.id.connect);
connect.setOnClickListener(this);
send = (Button)findViewById(R.id.send);
send.setOnClickListener(this);
}
#Override
public void onClick(View v) {
if(v == connect) {
bt.connect();
} else if(v == send) {
bt.sendData(sendtext.getText().toString());
}
}
}
When i try to connect to the chip, this is what i get from the logcat :
09-05 11:37:05.515: I/BluetoothPolicyService(2097): getBluetoothDataTransferAllowed
09-05 11:37:05.520: D/BluetoothPolicyService(2097): MDM: isProfileEnabled = true
09-05 11:37:05.520: D/BluetoothUtils(6868): isSocketAllowedBySecurityPolicy start : device null
09-05 11:37:05.525: V/BluetoothService.cpp(2097): createDeviceNative
09-05 11:37:05.525: V/BluetoothService.cpp(2097): createDeviceNative
09-05 11:37:05.525: V/BluetoothEventLoop.cpp(2097): onCreateDeviceResult
09-05 11:37:05.525: V/BluetoothEventLoop.cpp(2097): onCreateDeviceResult
09-05 11:37:05.525: E/BluetoothEventLoop.cpp(2097): onCreateDeviceResult: D-Bus error: org.bluez.Error.AlreadyExists (Already Exists)
09-05 11:37:05.525: V/BluetoothService.cpp(2097): discoverServicesNative
09-05 11:37:05.525: V/BluetoothService.cpp(2097): ... Object Path = /org/bluez/3094/hci0/dev_00_06_66_43_A1_E6
09-05 11:37:05.525: V/BluetoothService.cpp(2097): ... Pattern = , strlen = 0
09-05 11:37:10.660: V/BluetoothEventLoop.cpp(2097): onDiscoverServicesResult
09-05 11:37:10.660: V/BluetoothEventLoop.cpp(2097): ... Device Path = /org/bluez/3094/hci0/dev_00_06_66_43_A1_E6
09-05 11:37:10.660: E/BluetoothEventLoop.cpp(2097): onDiscoverServicesResult: D-Bus error: org.bluez.Error.ConnectionAttemptFailed (Host is down)
09-05 11:37:10.670: V/N(6868): Connection Failed : Service discovery failed
09-05 11:37:10.670: W/System.err(6868): java.io.IOException: Service discovery failed
09-05 11:37:10.675: W/System.err(6868): at android.bluetooth.BluetoothSocket$SdpHelper.doSdp(BluetoothSocket.java:462)
09-05 11:37:10.675: W/System.err(6868): at android.bluetooth.BluetoothSocket.connect(BluetoothSocket.java:240)
09-05 11:37:10.675: W/System.err(6868): at com.example.bluetooth.BtInterface$1.run(BtInterface.java:68)
I cannot figured out why this code doesn't work with the galaxy s3. I tried to search on google about bluetooth compatibility issues but i didn't find anything so far.
Thank you !
Guillaume
There are plenty of Bluetooth incompatibility issues with the new Android ICS. Apparently they messed around with the Bluetooth code to 'improve security'.
A bug I found and reported(which made my entire embedded board not able to connect for a week with any Android ICS device) was that when establishing a connection to an already paired device, Android ICS would require re-authentication - with or without PIN depends if you use Bluetooth SSP (I use it - this means that for me, on Android ICS connection of 2 bonded devices is still possible without user interaction - but it takes a bit longer).
Please vote this bug on Google Bugtracker - maybe someone will fix it...
Maybe this is your problem as well? Can you specify exactly at what line your code breaks?
Surround all your Bluetooth system code with try/catch, etc.
Anyway, the new Bluetooth behavior is very very bad, I heard of a lot of people not being able to connect to their old headset because of it.
Your code seems correct, but as Radu said, the new Bluetooth behaviour si not that good.
I did have quite some troubles myself (with Android 4.1+) and finally used BlueTerm as basis for my app, since it is opensource and is working (at least for the connexion part).
You can find its sources here :
http://pymasde.es/blueterm/
I hope it can help you !
D