Java SIP client like present in android - java

My requirement is to do a SIP registration using java servlet and then make an audio call. In android i have found simple way to do Android Supporting SIP however i am not able use same android code in java since SIP manager class is present in android.net packages. What should i use for my users to do SIP registration in java servlet.
below is android code
if (sipManager == null) {
sipManager = SipManager.newInstance(this);
}
SipProfile.Builder builder = null;
try {
builder = new SipProfile.Builder("7001", "XXX.XXX.X.XXX");
builder.setPassword("XXX");
sipProfile = builder.build();
Intent i = new Intent();
i.setAction("android.SipDemo.INCOMING_CALL");
PendingIntent pi = PendingIntent.getBroadcast(this, 0, i, Intent.FILL_IN_DATA);
sipManager.open(sipProfile, pi, null);
sipManager.setRegistrationListener(sipProfile.getUriString(), new SipRegistrationListener() {
public void onRegistering(String localProfileUri) {
}
public void onRegistrationDone(String localProfileUri, long expiryTime) {
}
public void onRegistrationFailed(String localProfileUri, int errorCode,
String errorMessage) {
}
});
} catch (ParseException pe) {
pe.printStackTrace();
} catch (SipException se) {
se.printStackTrace();
}

It is not clear from your question how do you envisage this to work. Servlets are server side, so if SIP messages are initiated from the server but I suspect what you really want is to initiate a SIP session, followed by an Audio stream established with some real-time streaming protocol from the client.
There are Java APIs for SIP, and Sun / Oracle had a standard API for integrating with telecoms networks using SIP and IMS: https://www.oracle.com/technetwork/java/introduction-jain-sip-090386.html
Not sure if they are still maintained.
However, I suspect that this is not what you really need. Maybe you should look at this client based WebRTC and SIP client:
http://www.doubango.org/sipml5/
Your JSP would serve this Javascript, which allows the user to initiate a SIP session and establish the Audio call.
From their documentation, it seems to be straightforward:
SIPml.init(
function(e){
var stack = new SIPml.Stack({realm: 'example.org', impi: 'bob', impu: 'sip:bob#example.org', password: 'mysecret',
events_listener: { events: 'started', listener: function(e){
var callSession = stack.newSession('call-audiovideo', {
video_local: document.getElementById('video-local'),
video_remote: document.getElementById('video-remote'),
audio_remote: document.getElementById('audio-remote')
});
callSession.call('alice');
}
}
});
stack.start();
}
);

Related

Issues with converting java to c#

I'm attempting to convert the code located at How to use signalr in android Service from java to c# and have been making some progress. I'm now stuck at the final method. The java code is:
private void startSignalR() {
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.getLogger());
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.start(clientTransport);
try {
signalRFuture.get();
} catch (InterruptedException | ExecutionException e) {
Log.e("SimpleSignalR", e.toString());
return;
}
mInstance.sendMessage(MainActivity.unm,"Hello All!");
String CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE,
new SubscriptionHandler2<String,LoginInfo>() {
#Override
public void run(final String msg,final LoginInfo loginInfo) {
final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.setAction(MY_ACTION);
intent.putExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
, String.class,LoginInfo.class);
}
Using a java to c# converter, this translated to:
private void startSignalR()
{
Platform.loadPlatformComponent(new AndroidPlatformComponent());
mInstance.setmHubConnection();
mInstance.setHubProxy();
ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger);
SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);
try
{
signalRFuture.get();
}
catch (Exception e) when (e is InterruptedException || e is ExecutionException)
{
// Log.e("SimpleSignalR", e.ToString());
return;
}
mInstance.sendMessage("", "Hello All!");
string CLIENT_METHOD_BROADAST_MESSAGE = "recievedMessage";
//String CLIENT_METHOD_BROADAST_MESSAGE = "messageReceived";
mInstance.mHubProxy.on(CLIENT_METHOD_BROADAST_MESSAGE, new SubscriptionHandler2AnonymousInnerClass(this)
, typeof(string), typeof(LoginInfo));
}
private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo>
{
private readonly SignalRSrv outerInstance;
public SubscriptionHandler2AnonymousInnerClass(SignalRSrv outerInstance)
{
this.outerInstance = outerInstance;
}
//JAVA TO C# CONVERTER WARNING: 'final' parameters are not available in .NET:
//ORIGINAL LINE: #Override public void run(final String msg,final LoginInfo loginInfo)
public override void run(string msg, LoginInfo loginInfo)
{
//JAVA TO C# CONVERTER WARNING: The original Java variable was marked 'final':
//ORIGINAL LINE: final String finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
string finalMsg = loginInfo.FullName + " says " + loginInfo.Password;
Intent intent = new Intent();
intent.Action = MY_ACTION;
intent.PutExtra("DATAPASSED", finalMsg);
sendBroadcast(intent);
}
}
This, of course, generated several errors in Visual Studio 2017.
First, the line Platform.loadPlatformComponent(new AndroidPlatformComponent()); generated the error Platform is inaccessible due to its protection level. Platform in Xamarin for Visual Studio 2017 is indeed protected and is a internal class in System and I cannot change this, so I'm at a loss as how to proceed with it. The same line generates the error The type or namespace name 'AndroidPlatformComponent' could not be found, these errors a numerous and not unexpected I just can't find an equivalent to AndroidPlatformComponent in Visual Studio 2017 so I'm at a loss as how to solve this one.
Next, on this line ClientTransport clientTransport = new ServerSentEventsTransport(mInstance.mHubConnection.Logger); generates the error The type or namespace name 'ClientTransport' could not be found, I was also unable to find an equivalent to this and again I'm at a loss as to proceed. Also on this line, .Logger is not defined for the hub connection, apparently it's .getLogger() in java, I was unable to find an equivalent for this one as well.
Next the line SignalRFuture<Void> signalRFuture = mInstance.mHubConnection.Start(clientTransport);' generates the error 1The type or namespace name 'SignalRFuture<>' could not be found, this seemes to be specific to SignalR, again, I am unable to find an equivalent.
The next one has me totally stumped, the line private class SubscriptionHandler2AnonymousInnerClass : SubscriptionHandler2<string, LoginInfo> generates the error The type or namespace name 'SubscriptionHandler2<,>' could not be found. I've looked everywhere online and read up on AnonymousInnerClass, but it was not help with this.
I'm hoping that the users here are more familiar with SignalR and the differences between c# functionality and java functionality. I'm not at all familiar with java nor am I familiar with SignalR and foreground services.
As it turns out, the last method in the java code I was converting was wiring up an event to pass the message received from the hub to the activity. In c# / Visual Studio (2017), that's done very differently which is why I didn't understand/recognize what was going on. So I created a handler in C# and execute a popup message for the message. This in itself may pose problems, but at least I know what's going on. This is the code I wrote to start SignalR from within the service and WireUp the handler:
private void startSignalR()
{
// Company, Department, and section are private variables
// their values are pulled from the intent bundle
// in the OnBind method, that code is:
// Bundle bundlee = intent.GetBundleExtra("TheBundle");
// MyUser = bundlee.GetParcelable("MyUser") as User;
// This information is put into the bundle when the user is logged in.
// I then pass that information to the SignalR client
// when I set the hub connection and placed on the querystring to the hub.
mInstance.setmHubConnection(username, firstname,lastname,company,department,section);
mInstance.setHubProxy();
try
{
// Connect the client to the hup
mInstance.mHubConnection.Start();
// Set the event handler
mInstance.WireUp();
}
catch (System.Exception e) when (e is InterruptedException || e is ExecutionException)
{
ShowMessage("Error: + e.Message)
}
}
This is the WireUp code, this is a method in the client code:
public void WireUp()
{
// set the event handler
mHubProxy.On("broadcastMessage", (string platform, string message) =>
{
if (OnMessageReceived != null)
OnMessageReceived(this, string.Format("{0}: {1}", platform, message));
});
}
As I had anticipated, the popup message won't appear when the app is in the background, so I'm researching a workaround

Discovering all services on the network using jmDNS on Android

I'm using the jmdns.jar from this project https://github.com/twitwi/AndroidDnssdDemo in my Android project.
I'm currently trying to find all services on my network. I can't use Android NSD, so please avoid suggesting it as a solution.
protected Object doInBackground(Object[] params) {
try {
WifiManager wifi = (WifiManager) getActivity().getSystemService(Context.WIFI_SERVICE);
final InetAddress deviceIpAddress = InetAddress.getByName(Formatter.formatIpAddress(wifi.getConnectionInfo().getIpAddress()));
multicastLock = wifi.createMulticastLock(getClass().getName());
multicastLock.setReferenceCounted(true);
multicastLock.acquire();
jmDNS = JmDNS.create(deviceIpAddress, "Android Device Discovery");
jmDNS.addServiceListener("_http._tcp.local.", new ServiceListener() {//_services._dns-sd._udp _http._tcp.local. _workstation._tcp.local.
#Override
public void serviceAdded(ServiceEvent serviceEvent) {
jmDNS.requestServiceInfo("", "", 1000);
}
#Override
public void serviceRemoved(ServiceEvent serviceEvent) {
}
#Override
public void serviceResolved(ServiceEvent serviceEvent) {
System.out.println(serviceEvent.getInfo().getHostAddress());
System.out.println(serviceEvent.getInfo().getName());
}
});
}catch(IOException e) {
Log.e(TAG, e.getMessage(), e);
}
}
The above code gives me the address and name of a printer on my network. That's great. What I would like is a TYPE that will catch all the services being broadcasted on my network. Android NSD had a _services._dns-sd._udpthat could be used for the type of service and find all services on the network. This doesn't work with jmDNS. I can't find anything in the limited documentation about this.
Do I need to go through and add all the service types myself? That is not a very clean solution.
I have the proper perms in my AndroidManifest.
Try adding the dot at the end, my jmdns app crashed without it..
Also try adding the .local. by yourself with the service type.

Android HTTP Requests Working In Simulator But Not On Wear Device

I am making a simple Android Wear app to control my thermostats, and I'm sending POST requests with Volley to control them. Everything works great in the Android Wear simulator (the request works), but, while the app does load on my Moto 360, the volley request gets called but invariably times out.
Why could my volley request be failing on my watch but working on the simulator? Other apps' requests succeed on my watch (for example, the built-in weather app can load up weather data in about 3 seconds). And, the weirdest part: I had the app working (successfully making volley requests) on my watch, and, about a day after I installed it to my watch from Android Studio, it suddenly stopped loading data for no apparent reason.
What I've tried so far:
I have requested the Internet permission in my manifest.xml.
I have increased the timeout to 30 seconds (see my code below), which didn't change anything.
I have tried tethering my computer and the simulator to my phone's connection via Bluetooth (to replicate the Bluetooth connection my physical watch has to my phone), and the simulator made the request successfully still (albeit with a two-second delay), ruling out the possibility of Bluetooth being too slow.
I made sure the API level is low enough for my Marshmallow-running watch (my watch and the app are both API level 23).
I tried doing a quick test request to Google before the request to the company's servers with my thermostat data, and while the Google request returns the site's HTML code in the simulator, it times out on my watch (thirty seconds after the request is initiated).
I tried putting some dummy data into the recycler view data should be loaded into, and the dummy data indeed showed up, ruling out that the recycler view is broken.
I deleted the app from my watch and reinstalled it, and deleted the companion from my phone, reinstalled it, and deleted it again, all to no avail.
A lengthy chat with Google Support did not produce anything meaningful.
Here's my code (from my main view's adapter):
public void refreshThermostatsRecyclerView(RequestQueue queue) {
String url = "https://mobile.skyport.io:9090/login"; // login call to the thermostats server Skyport
Log.w("myApp", "Starting /login call to Skyport"); // this gets called on simulator and watch
// Request a string response from the provided URL.
StringRequest stringRequest = new StringRequest(Request.Method.POST, url,
Response.Listener<String>() {
#Override
public void onResponse(String response) {
// Display the response string.
Log.w("myApp", "Response is: " + response); // this gets called on the simulator but not the watch
try {
// there's some code to parse the data.
} catch (JSONException e) {
Log.w("myApp", "catching an error parsing the json."); // never gets called.
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Log.w("myApp", "Skyport request didn't work! " + error); // this always gets called on the watch, with the error being a timeout error (com.Android.Volley.timeouterror) but never gets called in the simulator
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> m = new HashMap<>();
m.put("Referer", "app:/VenstarCloud.swf");
// here I put some more headers
return m;
}
#Override
protected Map<String, String> getParams() throws AuthFailureError {
Map<String, String> m = new HashMap<>();
m.put("version", "3.0.5");
m.put("email", userEmail);
m.put("password", userToken);
return m;
}
};
// Add the request to the RequestQueue.
int socketTimeout1 = 30000; // times out 30 seconds after the request starts on the watch
RetryPolicy policy1 = new DefaultRetryPolicy(socketTimeout1, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT);
stringRequest.setRetryPolicy(policy1);
queue.add(stringRequest);
}
Which is called from the onCreate() method in my Main Activity with this code:
RequestQueue queue = Volley.newRequestQueue(this);
refreshThermostatsRecyclerView(queue);
If you'd like to view the logs created by running this in the simulator and on the watch, they're on Google Drive here.
Edit 1: A reboot of my watch fixes the issue temporarily and allows the watch to make HTTP Requests again, but it breaks again once the watch disconnects from Bluetooth, connects to WiFi, disconnects from WiFi, and reconnects to Bluetooth (so it breaks every time I go across my apartment without my phone and then return).
Edit 2: I switched the volley requests all over to HTTPURLConnection Requests in an Async thread, and the same issues occur as with volley.
tl;dr: My app's Volley requests are working in the simulator but not on my Android Wear watch anymore (though Play Store-downloaded apps' similar requests work), how can I get a volley request to work again on my app on the watch?
As per these two conversations below, it seems that WiFi connectivity only allows Android Wear to connect to a phone over WiFi and not directly to the Internet. However, Android Wear 2.0 lets you use regular network APIs.
Direct internet connection on Android Wear?
Does Android Wear support direct access to the Internet?
So, for Android Wear 2.0+ Volley requests from wearable app should work.
If you want to use Android Wear <2.0, then:
On Wearable, in onCreate() add a key that indicates whether the phone should start collecting data.
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/shouldStart");
putDataMapReq.getDataMap().putBoolean(SHOULD_START_KEY, true);
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
PendingResult pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
On phone, in onDataChanged, check if wearable wants to start collecting data. If yes, start Volley request.
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
// DataItem changed
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo("/shouldStart") == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
boolean shouldStart = dataMap.getBoolean(SHOULD_START_KEY));
if(shouldStart) {
Volley.newRequestQueue(this).add(request);
}
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// DataItem deleted
}
}
Then, your Volley request's onResponse should pass data back to Wearable.
public void onResponse(String response) {
PutDataMapRequest putDataMapReq = PutDataMapRequest.create("/data");
putDataMapReq.getDataMap().putString(DATA_KEY, true);
PutDataRequest putDataReq = putDataMapReq.asPutDataRequest();
PendingResult pendingResult = Wearable.DataApi.putDataItem(mGoogleApiClient, putDataReq);
}
Finally, you can access data in your Wearable using onDataChanged and store it in your model for passing it onto adapter:
for (DataEvent event : dataEvents) {
if (event.getType() == DataEvent.TYPE_CHANGED) {
// DataItem changed
DataItem item = event.getDataItem();
if (item.getUri().getPath().compareTo("/data") == 0) {
DataMap dataMap = DataMapItem.fromDataItem(item).getDataMap();
parseAndpassToAdapter(dataMap.getString(DATA_KEY));
}
} else if (event.getType() == DataEvent.TYPE_DELETED) {
// DataItem deleted
}
}
You'll need Wearable.API to implement this and your class should implement DataApi.DataListener. For more information getting started, refer to Accessing the Wearable Data Layer and Syncing Data Items
Hope this helps.
I am also using volley on an Android wear app I built and I am running it on a Moto 360, I have run into the same problem a couple o times. Try restarting the device. Go to Settings > Restart. It sounds silly but it has worked for me.
You could try an alternative to volley if you can rule out the connection as the problem:
compile 'com.android.support:appcompat-v7:23.1.1'
compile 'com.android.support:support-v4:23.1.0'
compile 'com.android.support:design:23.1.0'
compile 'com.google.code.gson:gson:2.2.4'
compile 'com.google.api-client:google-api-client:1.20.0'
The versions are important.
Then to your request:
Map<String, String> contentParams = new HashMap<>();
InputStream is = null;
NetHttpTransport transport = null;
HttpRequest request = null;
HttpResponse resp = null;
HttpHeaders headers = new HttpHeaders();
JSONObject json = null;
try {
transport = new NetHttpTransport();
HttpRequestFactory factory = transport.createRequestFactory();
request = factory.buildPostRequest(new GenericUrl(url), null);
contentParams = getContentParameters();
headers.putAll(getHeaderParameters());
request.setHeaders(headers);
request.getUrl().putAll(contentParams);
resp = request.execute();
is = resp.getContent();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (is != null) {
string = getJSONFromInputStream(is);
json = new JSONObject(string);
}
} catch (Exception e) {
e.printStackTrace();
}
}
transport.shutdown();
protected Map<String, String> getContentParameters() {
Map<String, String> m = new HashMap<>();
m.put("version", "3.0.5");
m.put("email", userEmail);
m.put("password", userToken);
return m;
}
protected Map<String, String> getHeaderParameters() {
Map<String, String> m = new HashMap<>();
m.put("Referer", "app:/VenstarCloud.swf");
return m;
}
protected String getJSONFromInputStream(InputStream is) {
if (is == null)
throw new NullPointerException();
//instantiates a reader with max size
BufferedReader reader = new BufferedReader(new InputStreamReader(is), 8 * 1024);
StringBuilder sb = new StringBuilder();
try {
//reads the response line by line (and separates by a line-break)
String line;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
//closes the inputStream
is.close();
} catch (IOException e) {
e.printStackTrace();
}
}
return sb.toString();
}
Then just execute your code from a thread/asynctask/have it delay your frontend slightly
Edit:
Just in case there is a problem with appending a map:
for (Entry<String, String> entry : getHeaderParameters()) {
headers.put(entry.getKey(), entry.getValue());
}
for (Entry<String, String> entry : getContentParameters()) {
request.getUrl().put(entry.getKey(), entry.getValue());
}
Also as another note, make sure to change the return type from void on both those methods to Map
Is this not just the case of when the watch is connected to the phone via bluetooth the internet will not work, as wifi is turned off. If the watch is using wifi to connect to the phone then it will work.
I'm working on wear 2.0 app and just turn blueooth off on my phone for my watch to get internet connection.

AWS Android Chat App

I am trying to make an android chat application. I am thinking about making it with aws. But the problem is that I am unable to find any good tutorial for doing this and I have no idea how to do it.
So could anyone please suggest some tutorial for sending push notification or on how to make a chat application?
Firebase is well suited to this due to its "realtime database" feature. Here's a few tutorials I found by Googling
https://code.tutsplus.com/tutorials/how-to-create-an-android-chat-app-using-firebase--cms-27397
http://myapptemplates.com/simple-android-chat-app-tutorial-firebase-integration/
https://codelabs.developers.google.com/codelabs/firebase-android/#0
Check Socket.IO for android. ( https://github.com/socketio/socket.io-client-java )
Its really easy to write a chat application. But you need a server side.
Easy to write a simple server for this chat app.
Server reveice the all message from clients and broadcast the message, to all.
Gradle:
compile 'com.github.nkzawa:socket.io-client:0.5.1'
Android manifest:
<uses-permission android:name="android.permission.INTERNET" />
Java
public static Socket mSocket;
try {
mSocket = IO.socket("http://192.168.1.104:4444");
mSocket.connect();
} catch (URISyntaxException e) {
e.printStackTrace();
}
Send messsage to server:
MainActivity.mSocket.emit("message","Text here...");
Create a listener for another message:
MainActivity.mSocket.on("newMessage", onMessageArrive); // Oncreate
private Emitter.Listener onMessageArrive = new Emitter.Listener() {
#Override
public void call(final Object... args) {
getActivity().runOnUiThread(new Runnable() {
#Override
public void run() {
String data = (String)args[0];
// Here is all message. add it to list :) Or Push notif
}
});
}
};
// Server side:
var http = require('http');
var express = require('express'),
app = module.exports.app = express();
var io = require('socket.io').listen(app.listen(4444));
io.on('connection', function (socket) {
socket.on("message",function(msg){
io.sockets.emit('newMessage', msg);
});
});
Run:
npm install express
npm install socket.io
node filename.js
Just dont forget to check you IP! :)
Done! You have a Real Time Chat!!

Limit web service access to only one app

Right now I am working on a android app and I am totally new to this.
I want to make sure my web-service is only accessible via my app.
My background is PHP. In PHP I don't need to worry about anything like that, because everything runs on a server.
In case of Java and especially Android programming things are different. Even with encryption. Everybody can just open an APK and see how the web service gets accessed. So is there a way to hide or to obfuscate the access to a web service, so only my app will be able to use it?
For test purposes I didn't add any security or encryption. This is the basic call to a web server I am doing right now:
String url = "http://thisismyurl.com/a.php?action=get";
String result = Web.executeWeb(url);
public class Web {
public static String executeWeb(final String url) {
final StringBuilder sb = new StringBuilder();
Thread thread = new Thread(new Runnable() {
public void run()
{
try
{
InputStream is = (InputStream) new URL(url).getContent();
BufferedReader reader = new BufferedReader(new InputStreamReader(is));
String result, line = reader.readLine();
result = line;
while((line=reader.readLine())!=null){
result+=line;
}
sb.append(result);
//System.out.println(result);
//Log.i("My Response :: ", result);
} catch (Exception e)
{
// TODO: handle exception
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return sb.toString();
}
}
How would I hide this from the prying eyes of hackers? ;-) Is that even possible?
Thanks in advance!
Deploy client authentication using (self signed) certificates within TLS.
This kind of configuration can be enabled on most web servers and Java application servers, and you can normally also configure the web or application server in such a way that you can retrieve the certificate of the private key that the client used to authenticate itself.
Note that HTTPS uses SSL (or now TLS) before any web trafic, so you cannot program this in your application, it does require server configuration.
Check this link on how to configure for Apache 2.
Use your Application's ID ( like IMEI ) as parameter in your webservice call. You need to make a table in database at server side which will store all registered device. Now only these registered device can access your webservice. This is my idea, there should be other idea as well.

Categories