My target is to have a push-to-talk chat app in GSM/UMTS/LTE networks; initially I wanted use multicast addresses and peer-to-peer without overload the server; unfortunatly, after deep investigation, I discovered that multicast is not allowed in GSM/UMTS/LTE networks, therefore I have to use the server in order to bounce the VoIP packets. I' don't like very much this solution because I have to overload the server, but I didn't find any better solution. If you have an alternative solution is very much apprieciated...
Therefore I have to send VoIP from an android client to a server (PC), and viceversa. The server is in Java, it has to receive the VoIP packets and then to send the VoIP packets to other N clients; the server is a bouncer of VoIP packets.
I developped the code, but it doesn't work; I don't have any error, simply I had very bad VoIP service: I loose a lot of pieces and what I hear is very much noised... Where is the error? I suppose It should be in the server code; the server simply get the packet and resend them, without know that they are VoIP on RTP.
Please find below
the code I use to send the VoIP packets to server. It works because I don't have problems when I use it for individual call sending the VoIP packets directly from Android to Android; the code to receive in android the packets from server is very similar, so I don't recopy it. As you can see I use android.net.rtp .
the code I use on the Java server to bounce the VoIP packets
Thank you in advance, Fausto
// ANDROID CODE USED TO SEND VOIP TO SERVER
//Attribute definition
private static final AudioCodec myAudioCodec_COSTANTE = AudioCodec.PCMU ;
private static final int myAudioGroupTX_COSTANTE = AudioGroup.MODE_NORMAL ;
private static final int myAudioGroupRX_COSTANTE = AudioGroup.MODE_NORMAL ;
private static final int myRtpStreamTX_COSTANTE = RtpStream.MODE_SEND_ONLY ;
private static final int myRtpStreamRX_COSTANTE = RtpStream.MODE_RECEIVE_ONLY ;
private static final int myAudioManagerTX_COSTANTE = AudioManager.MODE_IN_COMMUNICATION;
private static final int myAudioManagerRX_COSTANTE = AudioManager.MODE_IN_COMMUNICATION;
//Method called for VoIP trasmission
myAudioStream = new AudioStream(localClientIP);
myAudioGroup = new AudioGroup();
myAudioManager = (AudioManager) myContext.getSystemService(Context.AUDIO_SERVICE);
myAudioGroup.setMode(myAudioGroupTX_COSTANTE);
myAudioStream.join(null);
myAudioStream.setCodec(myAudioCodec_COSTANTE);
myAudioStream.setMode(myRtpStreamTX_COSTANTE);
myAudioStream.associate(ipaddress_Server, port_Server)
myAudioStream.join(myAudioGroup);
myAudioManager.setMode(myAudioManagerTX_COSTANTE);
myAudioManager.setSpeakerphoneOn(false);
myAudioManager.setMicrophoneMute(false);
//JAVA SERVER CODE USED TO RECEIVE VOIP FROM ANDROID AND TO RESEND IT TO SERVER
DatagramSocket datagramSocket_RX_VoIP= new DatagramSocket();
DatagramSocket datagramSocket_TX_VoIP= new DatagramSocket();
int unicast_port_TX_VoIP = 5000 ;
String unicast_ip_TX_VoIP = "192.168.0.3";
Thread t = new Thread(new Runnable() {
public void run() {
try {
DatagramPacket myPacket;
while (true) {
myPacket = ManagePacket.initializePacket(); //Function to prepare the packe ; the problem is not here!!!
datagramSocket_RX_VoIP.receive(myPacket);
InetAddress ppp = InetAddress.getByName(unicast_ip_TX_VoIP);
myPacket.setAddress(ppp);
myPacket.setPort( unicast_port_TX_VoIP ) ;
datagramSocket_TX_VoIP.send(myPacket);
}
} catch (Exception ex) {
log.debug("Exception: " + ex.getMessage(), ex);
}
}
});
t.start();
You don't give enough detail about your application. With any UDP streaming application you need to address the following issues:
Network Jitter and Buffering: When a packet arrives, you cannot play the audio immediately after you receive it because the next packet might be later than expected and you will have a gap in your audio playback. The variance in the arrival rate is called network jitter. You need to buffer some amount of data before you try to play back. Usually you use some sort of ring buffer.
Packet loss: There will be packet losses with UDP. You need to "deal" with this. If you send 10 packets and packet #4 is missing, you can't play packet #3 then packet #5. It will sound bad. Ways to deal with this:
Loss Concealment: Try to minimize the bad effect off a packet lost. You can play silence (although this doesn't sound the best unless you fade it to silence). You can "estimate" the lost audio by generating a missing audio by examining the surrounding packets.
Forward Error Correction: Send packets more than once. There are numerous ways and schemes. The tradeoff is higher latency and more network utilization
Out of order arrivals: Packets may arrive out of order. Use the RTP sequence numbers to deal with this.
Audio streaming is not a trivial task. You can't just open a socket, send data, and play it on the other end and expect it to work. Your biggest concern with UDP streaming is network jitter and packet loss. If you don't want to deal with losses and you can have some extra latency, use TCP but be sure to buffer up enough audio before you start playing.
Related
I'm making a simple UDP chat program, and i would like the server to be able to send to the client without receiving data from it first. Normally, when it receives data from the client, the server gets the IP and port of the client, so it can communicate with it.
My server code:
package com.ageforce;
import java.io.*;
import java.net.*;
import java.util.Scanner;
public class ChatServer {
DatagramSocket server;
byte[] receivedData = new byte[1024];
Scanner scanner = new Scanner(System.in);
byte[] sentData;
DatagramPacket dp2 = new DatagramPacket(receivedData, receivedData.length);
public ChatServer() throws SocketException {
server = new DatagramSocket(7000);
}
public static void main(String[] args) throws SocketException {
ChatServer cs = new ChatServer();
Thread receiveMessage = new Thread(() -> {
while (true) {
try {
cs.server.receive(cs.dp2);
} catch (IOException e) {
e.printStackTrace();
}
String storedData = new String(cs.dp2.getData());
System.out.println(storedData);
}
});
Thread sendMessage = new Thread(() -> {
while (true) {
String sentMessage = cs.scanner.nextLine();
cs.sentData = sentMessage.getBytes();
// This is the area of the code where the server gets IP and port of client from the received data. I'd like this to be changed.
InetAddress getIP = cs.dp2.getAddress();
int port = cs.dp2.getPort();
DatagramPacket dp3 = new DatagramPacket(cs.sentData, cs.sentData.length, getIP, port);
try {
cs.server.send(dp3);
} catch (IOException e) {
e.printStackTrace();
}
}
});
sendMessage.start();
receiveMessage.start();
}
}
Is it possible to do this? Any reply is greatly appreciated.
How do i get the port and address of client without receiving data from it first?
UDP does not afford that possibility. It is a connectionless protocol, so the server doesn't even know that there is a client until it receives a message from it.
You could conceivably create some kind of preliminary application-level protocol whereby the client announces itself to the server before sending it any chat data, but nothing of the sort is part of UDP itself, and if that's something you want then you should consider using TCP instead, which does have a built-in concept of establishing a connection before sending any data.
In order to send an UDP message to something, you need to know the IP and port number to send it to. How? Well, you tell me.
The way your protocol works right now is that the clients know your hostname (which they let their system turn into an IP automatically), and the port number is hardcoded in the client app. The server knows which IP and port to send data back to by checking the 'sender' IP/port when it receives a call.
If you don't like your current protocol you'll need to figure out a different way to answer this question.
Even if you find a way, you'll find that this is mostly useless. The vast majority of end-users intentionally do not have a so-called publically routable IP address. You cannot reach them by design. In your current protocol, that IP/port combo you send back to isn't really the sending computer at all. It's some router, for example the router in their home. That router saw the outgoing UDP packet and is remembering for a while: Any traffic coming in on that port is supposed to go to that computer in this house.
Short of completely crazy stuff such as 'hole punching' (which skype used for a while, not sure if they still do, it's a complicated hack that doesn't always work and is surely not what you want here - you can search the web for that term), there's simply nothing you can do here. end-user systems aren't servers and cannot be reached like this.
Your run-of-the-mill chat apps will always have clients ping the server and then just keep that connection open as long as they can.
I am using UDP client to send about 20k requests per second with <1k data of every request. I need implement a UDP server via Java.
coding like following:
public void startRecieve() throws IOException {
udpSocket = new DatagramSocket(Constant.PORT);
byte[] buffer = new byte[Constant.SIZE];
udpPacket = new DatagramPacket(buffer, buffer.length);
int len;
while (true) {
udpSocket.receive(udpPacket);
len = udpPacket.getLength();
if (len > 0) {
// handing the data using other thread pool
}
}
}
Is there any way to make the UDP server packet loss be lower?
Thanks.
The packet loss is in the network, the only programming options are to
send less data e.g. compress it or
resend data on a loss so that less data is lost.
use TCP which handles packet loss for you.
use a library like Aeron which uses UDP and handles packet loss for you.
The best solution is almost always to fix the network to reduce the loss in the first place, but have a strategy which accepts some loss will happen.
Note: as UDP is a lossy protocol but TCP is not, many routers are optimised to drop UDP packets when the TCP load increases (as the router expects that any dropped TCP packet will just be sent again anyway)
This can mean that under load, you can see higher packet loss with UDP than TCP.
I'm creating a program on my Android phone to send the output of the camera to a server on the same network. Here is my Java code:
camera.setPreviewCallbackWithBuffer(new Camera.PreviewCallback() {
public void onPreviewFrame(byte[] data, Camera cam) {
try {
socket = new Socket("XXX.XXX.XXX.XXX", 3000);
out = socket.getOutputStream();
out.write(data);
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
camera.addCallbackBuffer(data);
}
The server is a NodeJS server:
time = 0
video_server.on 'connection', (socket) ->
buffer = []
socket.on 'data', (data) ->
buffer.push data
socket.on 'end', ->
new_time = (new Date()).getTime()
fps = Math.round(1000/(new_time - time)*100)/100
console.log fps
time = new_time
stream = fs.createWriteStream 'image.jpg'
stream.on 'close', ->
console.log 'Image saved.', fps
stream.write data for data in buffer
stream.end()
My terminal is showing about 1.5 fps (5 Mbps). I know very little about network programming, but I do know there should definitely be enough bandwidth. Each image is 640x480x1.5 at 18 fps, which is about 63 Mbps. The local network should easily be able to handle this, but my debugger in Android is giving me a lot of "Connection refused" messages.
Any help on fixing my bad network practices would be great. (I'll get to image compression in a little bit -- but right now I need to optimize this step).
You've designed the system so that it has to do many times more work than it should have to do. You're requiring a connection to be built up and torn down for each frame transferred. That is not only killing your throughput, but it can also run you out of resources.
With a sane design, all that would be required to transfer a frame is to send and receive the frame data. With your design, for each frame, a TCP connection has to be built up (3 steps), the frame data has to be sent and received, and the TCP connection has to be torn down. Worse, the receiver cannot know it has received all of the frame data until the connection shutdown occurs. So this cannot be hidden in the background.
Design a sane protocol and the problems will go away.
Is this working at all? I do not see where you are binding to port 3000 on the server.
In any case, if this is a video stream, you should probably be using UDP instead of TCP. In UDP, packets may be dropped, but for a video stream this will probably not be noticeable. UDP communication requires much less overhead than TCP due to the number of messages exchanged. TCP contains a lot of "acking" to make sure each piece of data reaches its destination; UDP doesn't care, and thus sends less packets. In my experience, UDP based code is generally less complex than TCP based code.
_ryan
Looking to make a Java stop-and-wait UDP server and client but I'm running into some problems starting off. I've made a simple UDP client and server without the stop-and-wait part, but I would now like to learn how to change it. How can I send ACKs and implement timeouts using java sockets ?
Could someone please post up some examples for me to use in my implementation ?
If you're implementing this in UDP, sending and receiving acknowledgements is up to you. This seems to be what you want for this stop and wait protocol. In terms of pseudocode, you would want something like:
int Send(msg)
{
char rcvBuf[];
sentBytes = sock.send(msg);
sock.rcv(rcvBuf);
return sentBytes;
}
int Recv(rcvBuf)
{
String ackMsg = "ACK";
length = sock.rcv(rcvBuf);
sock.send(ackMsg);
return length;
}
After every send, you wait for an acknowledgement message to come in, and every time you receive, you send an acknowledgement.
I'm currently developing an IDS/IPS that uses NetFlow data to draw assumptions whether there is an ongoing attack. I didn't afford an expensive CISCO router so I bought a LINKSYS router on which I installed DD-WRT. DD-WRT sends netflow v5 packets to your preferred machine so it's like having a CISCO router but older. Basically you get a $200-$500 router for $80 and a little tweaking.
I've set up the router, I'm getting the packets, I even used the DD-WRT provided tool for capturing rFlow (they named it like that but it's netflow v5) and everything works.
My application will have to do everything internally so that means i need to capture rflow packets, read them and draw the assumptions based on my readings.
I started developing in JAVA and set up a UDP daemon to listen on 2055 (port for receiving rflow packets). All good, i'm getting the packets but when i try to view the content i get some weird characters, like I'm dumping stuff from memory.
Here's my code for setting up the deamon and reading data.
try {
serverSocket = new DatagramSocket(2055);
while (true) {
DatagramPacket receivedPacket = new DatagramPacket(received, received.length);
serverSocket.receive(receivedPacket);
ByteArrayInputStream byteIn = new ByteArrayInputStream(receivedPacket.getData(),0,receivedPacket.getLength());
DataInputStream in = new DataInputStream(byteIn);
String input = "";
while( (input = in.readLine()) != null) {
System.out.println(input + "\n");
}
Inet4Address from = (Inet4Address) receivedPacket.getAddress();
System.out.println("FROM: " + from + "\nDATA: " + data[4]);
}
} catch (SocketException ex) {
System.out.println(ex.getMessage());
}
I have found a library called jflow..but there is no source code so i'm pretty skeptical on using it. I was wondering if somebody can tell me how can i actually read the content of the packets being sent to me. Since i'm at an early stage of development I am not bound to use JAVA, i could go for C++. My biggest problem, no matter the programming language is how to read the content of those packets so that I can draw the correct conclusions that i need for my other modules.
The rFlow / NetFlow v5 packets are a binary packet layout, so viewed as text they will appear, well, unreadable.
The packet format for the v5 packets is known, and can be found with a google search. This seems a good reference.
Note that the rFlow daemon on the dd-wrt has a long standing bug where it does not fill in the input or output interface fields correctly.