Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Writing audio to server over TCP socket

I'm trying to transmit real time mic recording to server over TCP socket and server to write input stream to a file. The connection is established but after some time, I'm getting connection refused error at my clientside.

Server Code:

    public class auServer extends Thread{
    private static ServerSocket serverSocket;
    private static int port = 3333; 

    public void run()
    {

        System.out.println("init success");
       while(true)
       {

          try
          {
              serverSocket = new ServerSocket(port);
              serverSocket.setSoTimeout(10000);
              Socket clientSoc = serverSocket.accept();
             System.out.println("Waiting for client on port " +serverSocket.getLocalPort() + "...");
             System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());
             InputStream in = clientSoc.getInputStream();
             while(in!=null)
             {
                 writeToFile(in);
             }
             System.out.println("socket");

             clientSoc.close();
          }catch(SocketTimeoutException s)
          {
             System.out.println("Socket timed out!");
             break;
          }catch(IOException e)
          {
             e.printStackTrace();
                     System.out.println("some io");
             break;
          } catch (Exception e) {
                    System.out.println("some e");
            e.printStackTrace();
        }
       }
    }

    private void writeToFile(InputStream in) throws IOException {
        // Write the output audio in byte
        String filePath = "8k16bitMono1.wav";
        short sData[] = new short[1024];
        byte[] bData = IOUtils.toByteArray(in);
        FileOutputStream os = null;
        try {
         os = new FileOutputStream(filePath);
        } catch (FileNotFoundException e) {
         e.printStackTrace();
        }
         System.out.println("Short wirting to file" + sData.toString());
         try {
          os.write(bData, 0, 2048);
         } catch (IOException e) {
          e.printStackTrace();
         }
        try {
         os.close();
        } catch (IOException e) {
         e.printStackTrace();
        }

    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
      try
      {
        Thread serverThread = new auServer();
        serverThread.run();
        System.out.println("runing");
       }catch(IOException e){
         e.printStackTrace();
      }
    }
}

and Client :

private void streamData(byte[] bData) throws UnknownHostException, IOException, InterruptedException {  //bData is byte array to transmit
    Thread.sleep(500);
    Socket client = new Socket("10.221.40.41",3333);
    OutputStream outToServer = client.getOutputStream();
    outToServer.write(bData);
    if(!isRecording)
        client.close();
}

What could be the problem? Thanks in advance.

like image 353
kAmol Avatar asked Jan 19 '16 10:01

kAmol


People also ask

Can you read and write from the same server socket?

for reading and writing on the same socket concurrently there is no problem, what really will happenn is that, you first when connect to the server using Socket, you must get output and input streams from this Socket object for writing and reading, then you can make a thread that listening for incoming messages from ...

Can a socket be used to send and receive messages?

You can send and recv from any connected socket. The direction of the data flow does not have anything to do with the client/server relationship. It is very common for clients and servers to both send and receive.

How listening to a socket works?

In a connection-oriented client-to-server model, the socket on the server process waits for requests from a client. To do this, the server first establishes (binds) an address that clients can use to find the server. When the address is established, the server waits for clients to request a service.


4 Answers

I'll comment on your code piece by piece.

private static ServerSocket serverSocket;

There's no reason for this to be static.

while(true)
{
    try
    {
        serverSocket = new ServerSocket(port);
        serverSocket.setSoTimeout(10000);

The last two lines should be ahead of the loop. This is the reason for the connection refusals, and it will also cause BindExceptions that you haven't mentioned. It isn't clear why you need the timeout.

             Socket clientSoc = serverSocket.accept();
             System.out.println("Waiting for client on port " +serverSocket.getLocalPort() + "...");

No you aren't. He's already connected. You were waiting before the accept().

             System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());
             InputStream in = clientSoc.getInputStream();
             while(in!=null)

Both the loop and the test are futile. The variable isn't null initially, and there is no way it can ever become null. The loop is futile because the writeToFile() method completely exhausts the input stream, so there is never anything more to read. This will be causing junk data, which you haven't mentioned.

             {
                 writeToFile(in);
             }
             System.out.println("socket");

A pointless message.

             clientSoc.close();

All the code from the line after accept() to here should be executed in a separate thread. The accept loop should do nothing but accept connections and start threads.

          }catch(SocketTimeoutException s)
          {
             System.out.println("Socket timed out!");

What timed out here was the accept(), as the listening socket is the only socket you've set a timeout on. I doubt that you need this.

             break;
          }catch(IOException e)
          {
             e.printStackTrace();
                     System.out.println("some io");

Another futile message.

             break;
          } catch (Exception e) {
                    System.out.println("some e");

Yet another one. When you get an exception, print the exception. Not some futile message of your own devising. Otherwise debugging becomes a mere guessing game.

            e.printStackTrace();
        }
       }
    }

    private void writeToFile(InputStream in) throws IOException {
        // Write the output audio in byte
        String filePath = "8k16bitMono1.wav";
        short sData[] = new short[1024];

Unused. Remove.

        byte[] bData = IOUtils.toByteArray(in);

Don't use this. It wastes space and adds latency. See below for the correct solution.

        FileOutputStream os = null;
        try {
         os = new FileOutputStream(filePath);
        } catch (FileNotFoundException e) {
         e.printStackTrace();
        }

Poor technique. This catch is in the wrong place. Code that depends on the success of code in a try block should be inside the same try block. At present you are falling through this try-catch as though the exception never happened, which will cause a NullPointerException in the code below.

         System.out.println("Short wirting to file" + sData.toString());

Another pointless message. Misspelt; sData has nothing in it; sData.toString() doesn't print anything useful regardless of the contents; and incorrect, as you aren't writing sData at all.

         try {
          os.write(bData, 0, 2048);

This writes exactly 2048 bytes, regardless of the amount read, which could be less or more. If it was less it will throw an ArrayIndexOutOfBoundsException or similar, which I would expect to see on the second call, although you haven't mentioned it, because the array should be zero length on the second and subsequent calls, if any. It should be a loop, of the general form:

int count;
byte[] buffer = new byte[8192]; // or more if you like
while ((count = in.read(buffer)) > 0)
{
    out.write(buffer, 0, count);
}

Back to your code:

         } catch (IOException e) {
          e.printStackTrace();
         }
        try {
         os.close();
        } catch (IOException e) {
         e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        // TODO Auto-generated method stub
      try
      {
        Thread serverThread = new auServer();
        serverThread.run();

This runs the run() method of the thread. It doesn't start a thread. It should be serverThread.start().

        System.out.println("runing");

Misspelt. Until you fix the start/run problem above, you won't see this message until after the server's run() method has exited.

and Client :

private void streamData(byte[] bData) throws UnknownHostException, IOException, InterruptedException {  //bData is byte array to transmit
    Thread.sleep(500);

Pointless. Remove. Don't put sleeps into networking code.

    Socket client = new Socket("10.221.40.41",3333);

Don't create a new connection per buffer. Use the same connection for the life of the client.

    OutputStream outToServer = client.getOutputStream();
    outToServer.write(bData);
    if(!isRecording)
        client.close();

This should be unconditional, and it should be elsewhere, along with the creation of the socket.

What could be the problem?

Problems. Plural. Multiple. See above.

like image 122
user207421 Avatar answered Oct 14 '22 22:10

user207421


The creation of the serversocket must be done outside of the loop. And for parallel connections you need to start a thread per connection.

Also apply the timeout to the established connections. A timeout on the serverSocket will end accepting after the timeout, this is nothing you want in a server.

...
public void run() {
    ServerSocket serverSocket;
    try {
        serverSocket = new ServerSocket(port);
    } catch (Exception ex) {
        ex.printStackTrace();
        return;
    }

    System.out.println("init success");

    while (true) {
        try {
            System.out.println("Waiting for client on port " + serverSocket.getLocalPort() + "...");
            final Socket clientSoc = serverSocket.accept();
            clientSoc.setSoTimeout(10000);

            System.out.println("Just connected to " + clientSoc.getRemoteSocketAddress());


            new Thread() {
                public void run() {
                    try {
                        InputStream in = clientSoc.getInputStream();
                        writeToFile(in);
                    } catch (Exception e) {
                        e.printStackTrace();
                    } finally {
                        try {
                            clientSoc.close();
                        } catch (Exception ignore) {
                        }
                    }
                }
            }.start();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
}
...
like image 31
bebbo Avatar answered Oct 14 '22 23:10

bebbo


I'm guessing your client side is an android application. Once, I tried to read and write data to an android application through a socket connection. Eventually, I did it by using the adb(android debugger bridge).

Lets say, there is a java application which creates a Socket with the port number 1992. And there is an android application, which creates a ServerSocket with the port number 1993.

Here comes the real deal!

Before you start running applications, you need to execute the following command in adb shell (or you can locate your adb in cmd/terminal and execute the command)

adb forward tcp:1992 tcp:1993    

After forwarding the port you can write and read data from java application to android application and wise-versa, using sockets' IO streams.

Desktop application code snippet :

while (flag) {
    try {
        final Socket socket = new Socket("localhost", 1992);
        new Thread(){
            @Override
            public void run() {                        
                while (flag) {                            
                    try {
                        new PrintWriter(socket.getOutputStream(), true).println(new Date().toString());
                    } catch (IOException ex) {
                        break;
                    }
                }
            }                    
        }.start();
    } catch (IOException ex) {
        // need port-forwarding
    }
}    

Android application code snippet :

while (flag) {
    try {
        final Socket socket = new ServerSocket(1993).accept();
        new AsyncTask<Void, Void, Void>() {
            @Override
            public Void doInBackground(Void... params) {
                while (flag) {
                    try {
                        String line = new BufferedReader(new InputStreamReader(socket.getInputStream())).readLine();
                        Log.d("", line);
                    } catch (IOException ex) {
                        return null;
                    }
                }
                return null;
            }
        }.execute();
    } catch (IOException ex) {
        break;
    }
}    

You can convert your audio to byte array and write it into a output stream. Hope my answer will be useful.

like image 3
CLOUGH Avatar answered Oct 14 '22 22:10

CLOUGH


I figured out the solution. The problem was actually with blocking Network I/O due to wrongly coded stream.

What I missed was

InputStream in = clientSoc.getInputStream();
DataInputStream DataIn =new DataInputStream(in)
while(DataIn!=null)
    {
        writeToFile(DataIn);
    }

and client side too

OutputStream outToServer = client.getOutputStream();
DataOutputStream out = new DataOutputStream(outToServer);
out.write(sData);
like image 1
kAmol Avatar answered Oct 14 '22 21:10

kAmol