I have created an application which gives statistics for the UDP packet loss in android. This is my architecture of the applications. 1) An application which multicast the UDP packets. Below is the code for it:
package rockwell.multicastserverproj;
import android.content.Context;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.support.design.widget.FloatingActionButton;
import android.support.design.widget.Snackbar;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.EditText;
import android.widget.Toast;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
public class MainActivity extends AppCompatActivity {
EditText txtMsg;
EditText txtPackets;
EditText txtMs;
EditText txtBytes;
EditText txtCount;
byte[] rtpData;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab);
fab.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show();
}
});
/*Thread thrClient = new Thread(new ReceiveMulticast());
thrClient.start();*/
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
public void onBtnClicked(View view)
{
Thread threadTotalPackets = new Thread(new SendMulticast());
threadTotalPackets.start();
Thread thread = new Thread(new MulticastPackets());
thread.start();
//Toast.makeText(this,"Message multicasted",Toast.LENGTH_LONG).show();
}
public class MulticastPackets implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 6500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtMs = (EditText)findViewById(R.id.txtMs);
txtBytes = (EditText)findViewById(R.id.txtBytes);
txtCount = (EditText)findViewById(R.id.txtCount);
int noOfPackets = Integer.parseInt(txtPackets.getText().toString());
int delayMS = Integer.parseInt(txtMs.getText().toString());
int packetSize = Integer.parseInt(txtBytes.getText().toString());
int cntPacket = Integer.parseInt(txtCount.getText().toString());
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
} catch (IOException e) {
e.printStackTrace();
}
for(int pcktCnt=1; pcktCnt<=noOfPackets; pcktCnt++) {
rtpData = new byte[packetSize];
int cnt = unsigned_int(pcktCnt);
byte[] seqArr = null;
seqArr = toBytes(cnt);
byte varFirst = 0xa;
byte varSecond = 0x5;
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
rtpData[i] = varFirst;
rtpData[i + 1] = varFirst;
}
else {
rtpData[i] = varSecond;
rtpData[i + 1] = varSecond;
}
}
for(int i=0;i<4;i++)
{
rtpData[i] = seqArr[i];
}
DatagramPacket requestPacket = new DatagramPacket(rtpData, rtpData.length, group, PORT);
try {
for(int i=0;i<cntPacket;i++) {
multiSocket.send(requestPacket);
Thread.sleep(delayMS, 0);
}
int test = fromByteArray(seqArr);
Log.i("Multicast", "Packet send. Sequence number is: " + test);
} catch (Exception e) {
e.printStackTrace();
}
int test = fromByteArray(seqArr);
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
MainActivity.this.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(MainActivity.this,"Packet sent",Toast.LENGTH_LONG).show();
}
});
}
}
public class SendMulticast implements Runnable{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
txtPackets =(EditText)findViewById(R.id.txtPackets);
txtBytes = (EditText)findViewById(R.id.txtBytes);
String requestString = txtPackets.getText().toString();
String strPackSize = txtBytes.getText().toString();
requestString = requestString +";" + strPackSize;
Log.i("reqstring",requestString);
byte[] requestData = new byte[requestString.length()];
requestData = requestString.getBytes();
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length, group, PORT);
multiSocket.send(requestPacket);
Log.i("multicastproj","message multicasted");
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
static int unsigned_int(int nb) {
if (nb >= 0)
return (nb);
else
return (256 + nb);
}
public byte[] toBytes(int i)
{
byte[] result = new byte[4];
result[0] = (byte) (i >> 24);
result[1] = (byte) (i >> 16);
result[2] = (byte) (i >> 8);
result[3] = (byte) (i /*>> 0*/);
return result;
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class ReceiveMulticast implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 4500;
WifiManager wifi = (WifiManager) getSystemService(getApplicationContext().WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.d("CreateMulticastServer", "Got request = " + requestString);
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
Another application which receives those multicast UDP packets
Service which runs continuously and receives the multicast packet:
package rockwell.packetstatistics;
import android.app.IntentService;
import android.content.Context;
import android.content.Intent;
import android.net.wifi.WifiManager;
import android.support.v4.content.LocalBroadcastManager;
import android.util.Log;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
/**
* Created by mmjoshi on 2/10/2016.
*/
public class PacketReceive_Service extends IntentService {
boolean flag = true;
int packetSize = 0;
public PacketReceive_Service() {
super("PacketReceive_Service");
}
@Override
protected void onHandleIntent(Intent intent) {
String strVar = intent.getStringExtra("vari");
Log.i("onstartservice","string is " + strVar);
Thread thread = new Thread(new PacketThread());
thread.setPriority(Thread.MAX_PRIORITY);
thread.start();
Thread thread1 = new Thread(new TotalPackets());
thread1.start();
}
public class PacketThread implements Runnable
{
@Override
public void run() {
InetAddress group = null;
MulticastSocket multiSocket = null;
WifiManager.MulticastLock mLock = null;
int prevSeqNo=0;
String strMissingPackets="";
int TotalpacketsReceived = 0;
try {
if(packetSize == 0)
packetSize = 1036;
byte[] requestData = new byte[packetSize];
int PORT = 6500;
byte varFirst = 0xa;
byte varSecond = 0x5;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
mLock = wifi.createMulticastLock("mylock");
mLock.setReferenceCounted(true);
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
while (flag) {
final DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
byte[] resultData = requestPacket.getData();
byte[] seqArr = new byte[4];
for(int i=0;i<4;i++){
seqArr[i] = resultData[i];
}
int seqNo = fromByteArray(seqArr);
Log.i("RecvPackets","multiple packet received # is: " + seqNo);
if(prevSeqNo!=seqNo)
{
TotalpacketsReceived++;
if(prevSeqNo!=0)
{
if((seqNo - prevSeqNo)>1)
{
for(int k=(prevSeqNo+1);k<seqNo;k++)
{
strMissingPackets += k + ", ";
sendResultMessage("Missing;" + String.valueOf(k));
Log.i("RecvPackets","Packet missing. Missing# is: " + k);
}
}
}
for(int i=4;i<packetSize;i+=2)
{
if(i%4 ==0) {
if(resultData[i] != varFirst || resultData[i+1] != varFirst)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
else {
if(resultData[i] != varSecond || resultData[i+1] != varSecond)
{
if(seqNo != 1) {
sendResultMessage("DataError;" + String.valueOf(seqNo));
Log.i("DataCheck", "Error in data");
}
}
}
}
prevSeqNo = seqNo;
Log.i("MulticastService", "Packet size is: " + packetSize + " Packet receive. Sequence number is: " + seqNo);
sendResultMessage("TotalPacketsReceived;" + String.valueOf(TotalpacketsReceived));
}
}
} catch (IOException e) {
Log.i("DEU Service", "In cache");
flag = false;
e.printStackTrace();
}
finally {
try {
if(multiSocket != null) {
if(group != null)
multiSocket.leaveGroup(group);
multiSocket.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if(mLock != null)
mLock.release();
}
}
}
private void sendResultMessage(String strPacks) {
Intent intent = new Intent("intData");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
private void sendTotalPackets(String strPacks) {
Intent intent = new Intent("intPacket");
intent.putExtra("result",strPacks);
LocalBroadcastManager.getInstance(this).sendBroadcast(intent);
}
public int fromByteArray(byte[] bytes) {
return bytes[0] << 24 | (bytes[1] & 0xFF) << 16 | (bytes[2] & 0xFF) << 8 | (bytes[3] & 0xFF);
}
public class TotalPackets implements Runnable{
@Override
public void run() {
byte[] requestData = new byte[1024];
InetAddress group = null;
MulticastSocket multiSocket = null;
int PORT = 5500;
WifiManager wifi = (WifiManager) getSystemService(Context.WIFI_SERVICE);
WifiManager.MulticastLock mLock = wifi.createMulticastLock("mylock");
mLock.acquire();
try{
group = InetAddress.getByName("230.0.0.1");
multiSocket = new MulticastSocket(PORT);
multiSocket.joinGroup(group);
} catch (IOException e) {
e.printStackTrace();
}
try{
while(true)
{
DatagramPacket requestPacket = new DatagramPacket(requestData, requestData.length);
multiSocket.receive(requestPacket);
String requestString = new String(requestPacket.getData(), 0, requestPacket.getLength());
Log.i("requestString",requestString);
String[] spltStr = requestString.split(";");
packetSize = Integer.parseInt(spltStr[1].toString());
Log.i("service","Packet size is: " + spltStr[1].toString() + " Total Packs: " + spltStr[0]);
sendTotalPackets(spltStr[0].toString());
/*txtMsg = (EditText)findViewById(R.id.txtMsg);
txtMsg.setText(requestString);*/
}
} catch (IOException e) {
e.printStackTrace();
}
try{
multiSocket.leaveGroup(group);
multiSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
mLock.release();
}
}
}
So, my question is, at the service side when I receives the packet mostly 5-7% of packets are loss. It means, if I send 1000 packets of 512 bytes at 5ms of interval 50-70 packet losses at the receiving end.
Is there a way I can reduce this packet loss? Or Is there any chances of my code for improvement so that packet loss can be reduced?
Thanks in advance.