I need to include a walki talkie in my app. I am always getting a registration failure -9 error code. I created 2 free Sip account (sip2sip.info, sip.linphone.org) and 1 commercial one (onsip.com). I added all those permission:
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.USE_SIP" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
and the following features:
<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" />
I am calling the above fonction in the onCreate:
void log_and_register()
{
try
{
c.DEBUG().ftrace("VOIP Supported: " + SipManager.isVoipSupported(c.ma()));
c.DEBUG().ftrace("SIP API Supported: " + SipManager.isApiSupported(c.ma()));
mSipManager = SipManager.newInstance(c.ma());
SipProfile.Builder builder = new SipProfile.Builder(c.config().getSIP_UserName(), c.config().getSIP_Domain());
builder.setPassword(c.config().getSIP_Password());
//builder.setProtocol("UDP"); //"TCP");
//builder.setPort(5060); //5080 5070
builder.setAutoRegistration(true);
mSipProfile = builder.build();
}
catch (ParseException pe)
{
c.DEBUG().ftrace("incapable of parsing domain name, username or password!");
c.DEBUG().ASSERT(0 == 1);
}
try
{
Intent intent = new Intent();
intent.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pendingIntent = PendingIntent.getBroadcast(c.ma(), 0, intent, Intent.FILL_IN_DATA);
mSipManager.open(mSipProfile, pendingIntent, null);
}
catch (SipException se)
{
c.DEBUG().ftrace("WALKIE TALKIE NOT WORKING - Sip Exception!!");
c.DEBUG().ASSERT(0 == 1);
}
if (ContextCompat.checkSelfPermission(c.ma(), Manifest.permission.USE_SIP) == PackageManager.PERMISSION_GRANTED)
c.DEBUG().ftrace("GRANTED!!!");
else
ActivityCompat.requestPermissions(c.ma(), new String[]{Manifest.permission.USE_SIP}, 1);
try
{
if (mSipManager.isRegistered(mSipProfile.getUriString()))
{
c.DEBUG().ftrace("already registered !!" + mSipManager.isRegistered(mSipProfile.getUriString()));
return;
}
}
catch (Exception e)
{
c.DEBUG().ftrace("NO!!");
}
try
{
//mSipManager.register(mSipProfile, 30, new SipRegistrationListener(){
//mSipManager.register(mSipProfile, 30000, new SipRegistrationListener(){
c.DEBUG().ftrace("THIS IS THE TRACE BEFORE REGISTATION : " + mSipProfile.getUriString());
mSipManager.setRegistrationListener(mSipProfile.getUriString(), new SipRegistrationListener()
{
public void onRegistering(String localProfileUri)
{
c.DEBUG().ftrace("Registering with SIP Server...");
}
// next version has it!!
public void onRegistrationTimeout() {}
public void onRegistrationDone(String localProfileUri, long expiryTime)
{
c.DEBUG().ftrace("SIP Ready");
}
public void onRegistrationFailed(String localProfileUri, int errorCode, String errorMessage)
{
// -9 signifie qu'il y a un appel en cours
c.DEBUG().ftrace("CANNOT REGISTER domain=" + c.config().getSIP_Domain() + " / username=" + c.config().getSIP_UserName());
c.DEBUG().ftrace("SIP ERROR MSG : localProfileUri=" + localProfileUri + " errorCode=" + errCode(errorCode) + " errorMessage=" + errorMessage);
}
});
}
catch (Exception e)
{
c.DEBUG().ftrace("Cannot initialise wakie talkie!");
c.DEBUG().ASSERT(0 == 1);
}
// https:github.com/aosp-mirror/platform_development/commit/a025796211f15c2796f8ea3208c066801aa250b6
initiateCall();
}
public SipAudioCall call = null;
public void initiateCall() {
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();
}
#Override
public void onCallEnded(SipAudioCall call) {
}
};
c.DEBUG().ftrace("rafael - Format="+mSipProfile.getUriString());
//call = mSipManager.makeAudioCall(mSipProfile.getUriString(), sipAddress, listener, 30);
call = mSipManager.makeAudioCall(mSipProfile.getUriString(), "sip:rafael.hogue#sip2sip.info", listener, 30);
} catch (Exception e) {
Log.i("WalkieTalkieActivity/InitiateCall", "Error when trying to close manager.", e);
if (mSipProfile != null) {
try {
mSipManager.close(mSipProfile.getUriString());
} catch (Exception ee) {
Log.i("WalkieTalkieActivity/InitiateCall",
"Error when trying to close manager.", ee);
ee.printStackTrace();
}
}
if (call != null) {
call.close();
}
}
}
I compile for Nougat because I am using deprecated function. Then I modified my code to compile with Oreo.
I used Firewall Voip Checker to check my connection with my SIP server and the test 1 is successful but the second one seam to be in an infinite loop. One of the result of the test one is captured my attention but I don't know what it means:
Check NAT type
100% / Blocked or could not reach STUN server (but it's green so I guess it pass the test??). I had the flag :
android.useDeprecatedNdk=true
I change it to false...
and I always get the return code "registration faild"
I hadded this fonction to see what the -9 error code was:
// FOR MORE DETAILS SEE
// Sip Error while registration
// How to send instant message via SIP
//https://developer.android.com/reference/android/net/sip/SipErrorCode
private String errCode(int iErrorCode)
{
String sErr = "";
switch (iErrorCode)
{
case CLIENT_ERROR:
sErr = "client error!!";
break;
case CROSS_DOMAIN_AUTHENTICATION:
sErr = "cross domain authentification!!";
break;
case DATA_CONNECTION_LOST:
sErr = "data connection lost!!";
break;
case INVALID_CREDENTIALS:
sErr = "invalid credentials!!";
break;
case INVALID_REMOTE_URI:
sErr = "invalid remote uri!!";
break;
case IN_PROGRESS:
sErr = "In progress!!";
break;
case NO_ERROR:
sErr = "No error!!";
break;
case PEER_NOT_REACHABLE:
sErr = "peer not reachable!!";
break;
case SERVER_ERROR:
sErr = "server error!!";
break;
case SERVER_UNREACHABLE:
sErr = "server unreachable!!";
break;
case SOCKET_ERROR:
sErr = "socket error!!";
break;
case TIME_OUT:
sErr = "time out!!";
break;
case TRANSACTION_TERMINTED:
sErr = "No transaction terminated!!";
break;
default:
sErr = "No error detected!!";
break;
}
return (sErr);
}
The error message is "In progress..." witch means that he is busy already but I don't know what it means.
I when thru the error code on Wikipedia to have clues of the potential problem:
https://en.wikipedia.org/wiki/List_of_SIP_response_codes#4xx.E2.80.94Client_Failure_Responses
I tried to find a SDK of a higher lever to implement my walki talki and found.
I search for the app wireshark but I only found it for a laptop and not for my android smartphone.
It's important for me to implement the walki talkie because I am creating a app to increase the security of primary school daycare and we need to communicate with each other.
I tried to change the port and the communication protocol and I tried the AutoRegistration flag to true.
I tried to make a phone call after the registration failed in case the open statement did the registration assuming it could be trying to register a second time.
I have no more idea!!
I will implementing a WIFI Walki Talki without a sip account.
Reference: stackoverflow.com/questions/11176988/…
Then I will save, on startup, the port information, ip adresse, username of every smart phones (use by my collegue) into my firebase (online database) in order to establish communication without asking anything to the user to make it automatique.
I am realizing that if I have trouble connecting with sample code that is suppose to work this probably means that my clients will have the same kinds of problemes wish I want to avoid.
I don't need to communicate with people that are not on the same network but I think this method would also work over the internet even for cliente that are on an other router if they are all connected to the internet.
Related
So i got my ESP32 and wanted to do some Porjects and I want to control them with an Android App, for example LED Stripes. I already did this with my Raspberry Pi where it runs perfectly.
I already tried some codes and it could connect to the Wifi. And my PC and even Raspberry Pi could connect to it but when i tried with my Smartphone i just didn't worked.
Here' my Android Code:
mainActivity.jre
connectButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
if (!IPAddress.getText().equals("") || IPAddress.getText() != null || !portNumber.getText().equals("") || portNumber.getText() != null){
return;
}
IPaddresse= IPAddress.getText().toString();
port=Integer.parseInt(portNumber.getText().toString());
try {
client = new Socket(IPaddresse,port);
pw = new PrintWriter(client.getOutputStream());
dataOutputStream= new DataOutputStream(client.getOutputStream());
msg.setText("Verbunden!");
} catch (UnknownHostException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
Permissions:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE"></uses-permission>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"></uses-permission>
ESP32 Code:
#include <WiFi.h>
const char* ssid="Name";
const char* password="password";
WiFiServer server(80 );
void setup() {
Serial.begin(115200);
Serial.println("start");
delay(1000);
WiFi.begin(ssid, password);
while (WiFi.status() != WL_CONNECTED) {
delay(1000);
Serial.println("Connecting to WiFi..");
}
Serial.println("Connected to the WiFi network");
Serial.println(WiFi.localIP());
server.begin();
}
void loop() {
WiFiClient client = server.available();
if (client) {
while (client.connected()) {
while (client.available()>0) {
char c = client.read();
client.write(c);
}
Serial.println(client.localIP());
delay(10);
}
}
}
Sorry for my English. And my Code isn't the best im just beginning to Code
Thanks
First on the ESP32 i suggest you add mDNS to your setup, this allows you to give your esp a name on the network like when you give your esp the name pietje then you can find it as pietje.local on your network.
This seems not to work properly with the socket class, but maybe i did something work. It did not finding the ip of it. It was the first time working with sockets. So i learned something new.
I tried your example and it did fault me to. With some short search i found this website:
https://www.tutorialspoint.com/sending-and-receiving-data-with-sockets-in-android
By adding you socket creation inside a thread it did work for me.
I hope this helps you ahead.
I have implemented agent live availability according to documentation. Problem is according to documentation it would land in OnResult method but every time response is landed in OnCompleted method, where I am unable to retrieve agent status from async variable.
Please Guide me if I am missing something or how to get live agent availability from OnCompleted.
My code (called within HomeFragment)
private void setupChatButton() {
try {
// Build a configuration object
ChatConfiguration chatConfiguration =
new ChatConfiguration.Builder(ORG_ID, BUTTON_ID,
DEPLOYMENT_ID, LIVE_AGENT_POD)
.build();
// Create an agent availability client
AgentAvailabilityClient client = ChatCore.configureAgentAvailability(chatConfiguration);
// Check agent availability
client.check().onResult((async, state) -> {
switch (state.getStatus()) {
case AgentsAvailable: {
// Toast.makeText(context, "Available Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = true;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.colorAccent));
break;
}
case NoAgentsAvailable: {
// Toast.makeText(context, "NOAGENTS Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
break;
}
case Unknown: {
// Toast.makeText(context, "UNKNOWN Chat", Toast.LENGTH_LONG).show();
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
break;
}
}
})
.onComplete(async -> {
Log.e("Home Fragment ", "Chat Call completed");
if (async.isComplete()) {
isAgentAvailable = true;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.colorAccent));
} else {
isAgentAvailable = false;
fabChat.setBackgroundTintList(ContextCompat.getColorStateList(context, R.color.grey));
}
// Toast.makeText(context, "Chat Completed!", Toast.LENGTH_LONG).show();
});
} catch (Exception e) {
Log.e(getContext().getClass().getSimpleName(), e.getMessage());
}
So turns out I was missing some dependencies in my gradle files, also the updated library versions require you to use minSDK 21 where I was using minSDK 19.
Following are the dependencies needed to support chat and preChat features:
implementation 'com.salesforce.service:chat-ui:3.1.0'
implementation 'com.salesforce.service:chat-core:3.1.0'
Apparently there are no references to it in official documentation.
Reference Agent
Reference Chat
I am developing an android application which has been using the Facebook sdk for 5 months now. Everything used to work fine until I logged out on a new device that had been successfully logged in. After that I successfully logged in, but when I tried to get the user’s information using the Request.newMeRequest I got null. So I debugged the problem and here is what I found out:
The session was successfully created with an access token
When trying to call the newMeRequest somewhere in the facebook sdk an exception was raised. The exception is “java.net.SocketException: Socket is closed”
I don’t understand how it is possible that the socket is closed. I searched a lot on the internet and here are some of the suggestions and things I tried to remove the bug:
I reinstalled the app and cleared all the cached data
I reinstalled the Facebook app
I rebooted the device
I deleted the application from the list of my Facebook apps (this revokes the access of the app to my data)
None of them seemed to produce results, so I gave up. I didn’t try the process for 4 hours when I got back home. There I reinstalled the Facebook app, after that I managed to successfully login and retrieve the user’s data once again. I didn't modify any of my code.
But the problems didn’t stop there. Today after several logins and logouts the issue appeared again and for the past 3 hours I have been able to make it work.
At this point I have really no idea neither why is this happening, nor how to fix it. Does anyone have any ideas what might be causing this kind of behavior?
I am using the Facebook sdk for Android v 3.8.0. I am also testing the app on multiple devices (I am not sure if that’s relevant), the problem so far appears only on Nexus 7 with Jelly Bean, on a Nexus 4 with Kit Kat this has never happened so far.
EDIT:
The code base is quite big, so I will start with some pieces that might be useful, and add more on request:
This handles the session
private Session.StatusCallback callback = new Session.StatusCallback() {
#Override
public void call(Session session, SessionState state,
Exception exception) {
onSessionStateChange(session, state, exception);
}
};
private void onSessionStateChange(Session session, SessionState state,
Exception exception) {
if(Utils.DEBUG) Log.d(TAG, "sessionStateChange fired");
FragmentManager fm = getSupportFragmentManager();
Fragment currentFragment = null;
switch (session.getState()) {
case CLOSED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION CLOSED");
handleLoginButtonOnClosedSession(fm, currentFragment);
break;
case CLOSED_LOGIN_FAILED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION CLOSED LOGIN FAILED");
handleLoginButtonOnClosedSession(fm, currentFragment);
break;
case CREATED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION CREATED");
break;
case CREATED_TOKEN_LOADED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION CREATED TOKEN LOADED");
UserWrapper.getCurrentUser(mContext).maintainFacebookToken(mContext);
break;
case OPENED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION OPENED");
break;
case OPENED_TOKEN_UPDATED:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION OPENED TOKEN UPDATED");
UserWrapper.getCurrentUser(mContext).maintainFacebookToken(mContext);
break;
case OPENING:
if(Utils.DEBUG) Log.d(this.getClass().getSimpleName(), "SESSION OPENING");
fm = getSupportFragmentManager();
currentFragment = fm.findFragmentById(R.id.fragment_container);
if(currentFragment instanceof SplashFragment) {
SplashFragment splashFragment = (SplashFragment) currentFragment;
splashFragment.hideLoginButtonForLogin();
}
break;
}
// Only make changes if the activity is visible
if (mIsResumed) {
if (state.isOpened()) {
// we don't want to clear the back stack if the
// home fragment is already showing
FragmentManager manager = getSupportFragmentManager();
Fragment previousFragment = manager.findFragmentById(R.id.fragment_container);
if(previousFragment == null || !(previousFragment instanceof HomeFragment)) {
clearFramgnets();
}
UserWrapper.getCurrentUser(mContext).maintainFacebookToken(mContext);
// If the session state is open:
// Show the authenticated fragment
showFragment(HOME, false);
} else if (state.isClosed()) {
if(Utils.DEBUG) Log.d(TAG, "showing splash");
clearFramgnets();
// If the session state is closed:
// Show the login fragment
showFragment(SPLASH, false);
}
}
}
#Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
uiHelper.onActivityResult(requestCode, resultCode, data);
if(Utils.DEBUG) Log.d(TAG, "Main Activity - onActivityResult called: requestCode="
+ requestCode + " resultCode:" + resultCode);
}
Here I try to get the user from Facebook
public void logOnApp(final LoginManager loginManager,
final AppUserLoadedCallback callback) {
if (mUserId == null || mUserId.getIdFromProvider() == null || getAuthToken() == null) {
// make request to the /me API
Request.newMeRequest(Session.getActiveSession(),
new Request.GraphUserCallback() {
// callback after Graph API response with sUser object
public void onCompleted(GraphUser user,
Response response) {
if (user != null) {
mUserId = new Id(Provider.FACEBOOK, user
.getId());
loginManager.increaseSuccesfulRetrievalsCount();
fetchUserAuthData(loginManager, callback);
} else {
// The login has been unsuccessful, if we have reached
// the maximum login retries -> logout, else attempt again.
if (loginManager.maxRetriesCountReached()) {
loginManager.mLogoutRunnable.run();
} else {
loginManager.increaseRetriesCount();
logOnApp(loginManager, callback);
}
}
}
}).executeAsync();
} else {
fetchUserAuthData(loginManager, callback);
}
}
Any new ideas about why is this happening would be really helpful!
I'm writing a bluetooth HID server for a small and very simple bluetooth remote. I'm following the documentation here.
My application's permission include:
<uses-permission android:name="android.permission.BLUETOOTH"/>
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
And this is my BluetoothServerSocket reading connection-accepting thread:
private class AcceptThread extends Thread {
public void run() {
BluetoothSocket socket = null;
while(true) {
try {
socket = MyBluetoothServerSocket.accept(); // problematic line
} catch(IOException e) {
Log.i(BLUETOOTH_SERVICE, e.toString());
break;
}
if(socket != null) {
readInput(socket);
try {
MyBluetoothServerSocket.close();
} catch (IOException e) {
Log.i(BLUETOOTH_SERVICE, e.toString());
}
} else {
Log.i(BLUETOOTH_SERVICE, "Could not accept a connection from the socket.\n");
}
break;
}
}
}
MyBluetoothServerSocket is a socket constructed like this:
MyBluetoothAdapter.listenUsingRfcommWithServiceRecord("MyService", UUID.fromString("00001124-0000-1000-8000-00805f9b34fb"));
The UUID I'm using above is the only one my remote control device reports through the following method:
MyBluetoothDevice.getUuids();
And MyBluetoothAdapter is just the default adapter:
BluetoothAdapter.getDefaultAdapter();
The rest of the code involved is minimal (making sure bluetooth is on, selecting the correct device) and working correctly. The remote is bonded to the phone.
The line marked as problematic in the code above (accept()) never returns i.e. it blocks forever. What am I doing wrong?
edit: I've tried MyBluetoothAdapter.listenUsingInsecureRfcommWithServiceRecord without success.
HID is based on the L2CAP bluetooth profile (protocol?), which is not implemented (line 107) in Android as of October 2013.
This makes it currently impossible to connect to a HID device.
I usually use this
private void ensureDiscoverable() {
if(D) Log.d(TAG, "ensure discoverable");
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
But that prompts a user confirmation. Is there a way to bypass this programmatically?
Also, I suppose there are no "news" on the "always discoverable mode" ?
After some research I concluded that setting discoverable timeout without user interaction it's only possible with root access (as already suggested in the previous answer). However for someone who need that here is the necessary solution:
private void ensureBluetoothDiscoverability() {
try {
IBluetooth mBtService = getIBluetooth();
Log.d("TESTE", "Ensuring bluetoot is discoverable");
if(mBtService.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Log.e("TESTE", "Device was not in discoverable mode");
try {
mBtService.setDiscoverableTimeout(100);
// mBtService.setScanMode(BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, 1000);
} catch(Exception e) {
Log.e("TESTE", "Error setting bt discoverable",e);
}
Log.i("TESTE", "Device must be discoverable");
} else {
Log.e("TESTE", "Device already discoverable");
}
} catch(Exception e) {
Log.e("TESTE", "Error ensuring BT discoverability", e);
}
}
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
And then create a new package android.bluetooth, place two files inside IBluetooth.aidl and IBluetoothCallback.aidl and put inside the code as shown here.
This will allow to access functions that are not available on the standard API, but for some of them you will need permission to "write secure settings" (the comment line above is where you will get that exception for lack of permissions of the process/user).
That's what I did and it works fine for me :
Method :
public void makeDiscoverable (int timeOut){
Class <?> baClass = BluetoothAdapter.class;
Method [] methods = baClass.getDeclaredMethods();
Method mSetScanMode = methods[44];
try {
mSetScanMode.invoke(Util.mBluetoothAdapter, BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE, timeOut);
} catch (Exception e) {
Log.e("discoverable", e.getMessage());
}
}
Add permission :
<uses-permission android:name="android.permission.WRITE_SETTINGS" />
Nothing - It still needs user confirmation.
BEing always discoverable is a drain on battery - so there is no easy solution
Also it is a privacy issue.
Its better to ask the user.
After testing and searching for various options, I have created these lines that don't require an user interaction. I hope it helps:
In method:
try{
Method metodo = BluetoothAdapter.class.getMethod("setScanMode", int.class);
try {
metodo.invoke(bluetoothAdaptador, SCAN_MODE_CONNECTABLE_DISCOVERABLE);
}catch (InvocationTargetException e) {
e.printStackTrace();
}
}catch (NoSuchMethodException | IllegalArgumentException | IllegalAccessException e) {
Log.e(TAG, "Fallo al hacer visibile el dispositivo.", e);}