I'm trying to make an audio loop by a connection server (Java) - Client (Android) in real time. Server (PC / Java) client sends data to the client (mobile / Android) and return.
I put a piece of code to clarify: - Server
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
/**
* This class implements a TCP Server.<p>
*/
public class GTCPServer {
public static final int SERVER_PORT = 4444; // Port number
private boolean running = true; // Boolean to control stream
private ServerSocket serverSocket;
// Input-Output streams:
private DataInputStream dis;
private DataOutputStream dos;
// Buffer:
private byte[] bytes;
private static final int BUFFER_SIZE = 512 * 4; // Size
/**
* Constructor. Starts Server.
*/
public GTCPServer() {
bytes = new byte[BUFFER_SIZE]; // Create buffer
// Put values to test:
bytes[0] = 3;
bytes[BUFFER_SIZE - 1] = 7;
try {
// Create Server Socket and wait connections.
serverSocket = new ServerSocket(SERVER_PORT);
System.out.println("Conecting...");
// Within accept methode we are waiting connection.
// When it's ready, create Client Socket:
Socket client = serverSocket.accept();
System.out.println("Receiving...");
try {
// Streams:
dis = new DataInputStream(client.getInputStream());
dos = new DataOutputStream(client.getOutputStream());
} catch (Exception e) {
System.out.println("Error.");
e.printStackTrace();
}
} catch (Exception e) {
System.out.println("Error.");
e.printStackTrace();
}
} // GTCPServer()
/**
* Send (write) a byte[] buffer within TCP.
* @param buffer - Data.
* @param offset - Position.
* @param count - Number of bytes to write.
*/
public void write(byte[] buffer, int offset, int count) {
try {
dos.write(buffer, offset, count); // Write
} catch (IOException e) {
e.printStackTrace();
}
} // write()
} // GTCPServer
Client:
import android.util.Log;
import java.io.*;
import java.net.InetAddress;
import java.net.Socket;
import com.appacoustic.java.g.G;
public class GTCPClient_A {
public static final String SERVER_IP = "192.168.1.101"; // Server IP (PC)
public static final int SERVER_PORT = 4444; // Port number
private boolean running = true; // Boolean to control stream
// Input-output streams:
private DataInputStream dis;
private DataOutputStream dos;
// Buffer:
private byte[] bytes;
private static final int BUFFER_SIZE = 512 * 4; // Size
/**
* Constructor.
*/
public GTCPClient_A() {
bytes = new byte[BUFFER_SIZE]; // Create buffer
} // GTCPClient_A()
/**
* Execute Thread. It isn't override because we are using a subclass (connectTask) wich extends AsyncTask.
*/
public void run() {
try {
// Get InetAddress (IPv4 Server)
InetAddress serverAddr = InetAddress.getByName(SERVER_IP);
Log.e("GTCPClient_A", "Conecting...");
// Create a Socket ti connect with Server:
Socket socket = new Socket(serverAddr, SERVER_PORT);
try {
dis = new DataInputStream(socket.getInputStream());
dos = new DataOutputStream(socket.getOutputStream());
int lap = 0; // Para llevar la cuenta de las vueltas
while (running) {
dis.read(bytes); // Leemos por TCP
System.out.println("IN_ini_["+lap+"]: "+bytes[0]);
System.out.println("IN_fin_["+lap+"]: "+bytes[BUFFER_SIZE - 1]);
G.toc = System.currentTimeMillis();
G.ticToc();
G.tic = G.toc;
dos.write(bytes); // Escribimos por TCP
System.out.println("OUT_ini_["+lap+"]: "+bytes[0]);
System.out.println("OUT_fin_["+lap+"]: "+bytes[BUFFER_SIZE - 1]);
lap++;
}
} catch (Exception e) {
Log.e("GTCP", "SERVIDOR: Error", e);
} finally {
socket.close();
}
} catch (Exception e) {
Log.e("GTCP", "CLIENTE: Error", e);
}
} // run()
} // GTCPClient_A
I have programmed it via Bluetooth and TCP without good results. There is too much delay (around 5 seconds). My surprise was that when trying to deploy the Client in Java instead of Android, does work (the code is almost identical). In fact I speak into the microphone (I scheduled JASIOHost ASIO drivers), from the computer where I have the Server, TCP data travels to another computer within the same WiFi, return and hear real-time perfectly speakers in the Server computer.
So, it appears the problem is something Android. But I what I want is to use a smartphone or tablet as a Client.
I've tested with this line at Client too: android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); // Priority
Find Wear months trying unsuccessfully solution ...
Finally the solution has been UDP. It's faster than TCP or Bluetooth. I put you code here. Now Server is Android:
public class GUDPServer_A {
private int PORT_NUMBER = 4444; // Nº de puerto de conexión. Usamos el mismo para Servidor y Cliente (para no liar)
private DatagramSocket serverSocket; // Socket Servidor
private DatagramPacket inPacket; // Paquete de entrada
private DatagramPacket outPacket; // Paquete de salida
private boolean running = true; // Booleano para indicar que se está a la escucha del Cliente
// Buffers:
public static final int BUFFER_SIZE = 1024 * 4;
public static byte[] bytes_in;
public static byte[] bytes_out;
public GUDPServer_A() {
bytes_in = new byte[BUFFER_SIZE];
bytes_out = new byte[BUFFER_SIZE];
try {
serverSocket = new DatagramSocket(PORT_NUMBER); // Sólo se hace una vez ya que siempre estamos mandando por el mismo puerto
System.out.println("Servidor UDP en marcha.");
} catch (SocketException e) {
System.out.println("Socket: "+e.getMessage());
} catch (IOException e) {
System.out.println("IO: "+e.getMessage());
}
} // GUDPServer_A()
/**
* Ejecución del hilo. El método no está sobreescrito porque usamos una subclase (connectTask) que extiende de AsyncTask.
*/
public void run() {
android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO); // Le damos prioridad "-19" al Thread (Lo máximo es -20)
int lap = 0; // Para llevar la cuenta de las vueltas
while (running) {
read(bytes_in); // Recibimos el paquete desde UDP
// Procesamos (de momento lo dejamos igual, simplemente clonamos):
bytes_out = bytes_in.clone();
G.toc = System.currentTimeMillis();
G.ticToc();
G.tic = G.toc;
write(bytes_out); // Enviamos el paquete de vuelta
Log.d("Vuelta:", ""+lap);
lap++;
}
} // run()
/**
* Envía (escribe) un buffer de bytes por UDP.
* @param buffer - La memoria intermedia donde se almacenan los datos a enviar.
*/
public void write(byte[] buffer) {
outPacket = new DatagramPacket(buffer, inPacket.getLength(), inPacket.getAddress(), inPacket.getPort());
try {
serverSocket.send(outPacket); // Enviamos el paquete
} catch (IOException e) {
e.printStackTrace();
}
} // write()
/**
* Recibe (lee) un buffer de bytes por UDP.
* @param buffer - La memoria intermedia donde se almacenan los datos a recibir.
*/
public void read(byte[] buffer) {
inPacket = new DatagramPacket(buffer, buffer.length);
try {
serverSocket.receive(inPacket); // Recibimos el paquete
} catch (IOException e) {
e.printStackTrace();
}
} // read()
/**
* Cierra la conexión.
*/
public void stop() {
if (serverSocket != null) {
serverSocket.close();
}
} // stop()
} // GUDPServer_A
And Client is Java:
public class GUDPClient {
private int PORT_NUMBER = 4444; // Nº de puerto de conexión. Usamos el mismo para Servidor y Cliente (para no liar)
private DatagramSocket clientSocket; // Socket Cliente
private DatagramPacket inPacket; // Paquete de entrada
private DatagramPacket outPacket; // Paquete de salida
private InetAddress host; // Dirección IP del Servidor (LG L5)
public static final String IP_LG = "192.168.1.102"; // IP del Servidor (LG L5)
public static final String IP_TABLET = "192.168.1.105"; // IP del Servidor (Tablet)
/**
* Constructor.
*/
public GUDPClient() {
try {
clientSocket = new DatagramSocket(); // No hace falta darle un nº de puerto (se lo damos al paquete)
host = InetAddress.getByName(IP_LG); // Obtenemos el host del Servidor (LG L5)
//host = InetAddress.getByName(IP_TABLET); // Obtenemos el host del Servidor (Tablet)
System.out.println("Cliente UDP conectado.");
} catch (SocketException e) {
System.out.println("Socket: "+e.getMessage());
} catch (IOException e) {
System.out.println("IO: "+e.getMessage());
}
} // GUDPClient()
/**
* Envía (escribe) un buffer de bytes por UDP.
* @param buffer - La memoria intermedia donde se almacenan los datos a enviar.
*/
public void write(byte[] buffer) {
outPacket = new DatagramPacket(buffer, buffer.length, host, PORT_NUMBER);
try {
clientSocket.send(outPacket); // Enviamos el paquete por UDP
} catch (IOException e) {
e.printStackTrace();
}
} // write()
/**
* Recibe (lee) un buffer de bytes por UDP.
* @param buffer - La memoria intermedia donde se almacenan los datos a recibir.
*/
public void read(byte[] buffer) {
inPacket = new DatagramPacket(buffer, buffer.length);
try {
clientSocket.receive(inPacket); // Recibimos el paquete procesado desde UDP
} catch (IOException e) {
e.printStackTrace();
}
} // read()
/**
* Cierra la conexión.
*/
public void stop() {
if (clientSocket != null) {
clientSocket.close();
}
} // stop()
} // GUDPClient
One important thing is setting fast Threads.
Android: android.os.Process.setThreadPriority(android.os.Process.THREAD_PRIORITY_URGENT_AUDIO);
Java: thread.setPriority(Thread.MAX_PRIORITY);