1

I asked before:https://stackoverflow.com/questions/35344535/dcom-alternative-for-java-sending-audio-streaming-in-the-same-machine

I want to capture Audio from my Microphone and send to clients (0 or 4) using One Server...

PD: I was checking this question: Sending audio stream over TCP, UnsupportedAudioFileException but is oriented to One server with One Client solution. Other Question: Java - Broadcast voice over Java sockets Streaming audio from microphone with Java

I was thinking to use TCP (Server/Client Model), but the Server and 4 Clients will be receiving the data (audio streaming) and I don't know if is possible to implement this alternative (I'm worried about the port managment)....

HERE my preliminary (it still is Not working, because I have doubts and I thinking how solve my concers)

Variables:

static boolean bThreadCapture = false;
static boolean bThreadServer = false;
static ByteArrayOutputStream myByteArrayOutStream;
ExecutorService myServerPool = Executors.newFixedThreadPool(4);
static Thread myThreadServer = null;

Now my headache

  final int iServerPort = 2370;
  final AudioFormat myAudioFormat = new AudioFormat(8000,8,1,false, true);
  final DataLine.Info myDataLineInfo = new DataLine.Info(TargetDataLine.class, myAudioFormat);
  if (!AudioSystem.isLineSupported(myDataLineInfo)) {
    System.out.println("Line not supported");
    System.exit(0);
  }
  try {
    final TargetDataLine myTargetDataLine = (TargetDataLine) AudioSystem.getLine(myDataLineInfo);
    myTargetDataLine.open(myAudioFormat);
    myByteArrayOutStream = null;

    //BEGIN definition Thread for CAPTURING AUDIO FROM MIC
    Runnable runnAudioCapture = new Runnable() {
      int bufferSize = (int) myAudioFormat.getSampleRate()* myAudioFormat.getFrameSize();
      byte buffer[] = new byte[bufferSize];
      public void run() {
        myByteArrayOutStream = new ByteArrayOutputStream();
        bThreadCapture = true;
        while (bThreadCapture) {
          try {
            int count = myTargetDataLine.read(buffer, 0, buffer.length);
            if (count > 0) {
              myByteArrayOutStream.write(buffer, 0, count);
              //  HERE: I need to send the bytes of Sound to all active Threads Client (from 1 until 4)
              //  But, How to know what (how much and which) are active threads client?
              //  How to access to each Executor?
            }
          } catch (IllegalArgumentException | ArrayIndexOutOfBoundsException e) {
            System.err.println("TargetDataLine problems: " + e);
          }
        }
        try {
          if (myByteArrayOutStream != null) myByteArrayOutStream.close();
        } catch (IOException e) {  }
      }
    };
    //END definition Thread for CAPTURING AUDIO FROM MIC


    //BEGIN definition Thread for ATTENDANT SERVER CLIENT (Still not defined) 
    myThreadServer = new Thread() {
      @Override
      public void run() {
        try {
          SrvrSocketProducer = new ServerSocket(iServerPort);
          System.out.println("Server Listening on port number: "+iServerPort);
        } catch (IOException e) {
          System.out.println("Could not listen on port: "+iServerPort);
        }
        new Thread(runnAudioCapture).start();  //BEGIN AUDIO CAPTURE
        while(bThreadServer) {
          Socket clientSocket = null;
          try {
            clientSocket = SrvrSocketProducer.accept(); 
          } catch (IOException e) {
            if(!bThreadServer) {
              System.out.println("Server Stopped.") ;
              break;
            }
            throw new RuntimeException("Error accepting client connection", e);
          }
          myServerPool.execute(new runnWorkerListener(clientSocket,myAudioFormat));
        }
        myServerPool.shutdown();
        bThreadCapture = false;  //STOP AUDIO CAPTURE
      }
    };
    //END definition Thread for ATTENDANT SERVER CLIENT (Still not defined) 
    myThreadServer.start();
  } catch (LineUnavailableException ex) {
    System.out.println(ex.toString());
  }

Questions:

(merged in runnAudioCapture code to locate help)

1. HERE: I need to send the bytes of Sound to all ACTIVE Threads Client (from 1 until 4)
2. But, How to know what (how much and which) are active threads client?
3. How to access to each Executor?

Now the worker threads--

  class runnWorkerListener implements Runnable {
    Socket innerClientSocket = null;
    AudioFormat innerAdfmt = null;
    public runnWorkerListener(Socket clientSocket, AudioFormat audioFormat) {
      innerClientSocket = clientSocket;
      innerAdfmt = audioFormat;
    }
    public void run() {
      try {
        InputStream input  = innerClientSocket.getInputStream();
        OutputStream output = innerClientSocket.getOutputStream();
        // Now How Can I to Comunicate with runnAudioCapture?
        while (RunningClientAttender /*This variable still is not defined*/) {
          // I need to send (thread client here Not defined) EACH bytes from runnAudioCapture
        }
        output.close();
        input.close();
        System.out.println("Request processed: ");
      } catch (IOException e) {
        //report exception somewhere.
        e.printStackTrace();
      }
    }
  }

Questions:

(merged in runnWorkerListener code to locate help)

1. Now How Can I to Comunicate with runnAudioCapture?
2. I need to send (thread client here Not defined) EACH bytes from runnAudioCapture

My Doubt are related with: One thread dedicated to audio Capture One thread dedicated to receive clients (1, 2 3, or 4) using Pool and creating threads worker (One thread worker to communicate with "remote" client)

I don't know handle synchronized the Capturer thread Capturer with Each Worker thread...

Thank you...

Community
  • 1
  • 1
QA_Col
  • 1,095
  • 9
  • 23

1 Answers1

0

Unfortunately, in Java, a stream is only meant to be used by one person at a time. You have one stream, myByteArrayOutStream, and you want to share it between 4 TCP connections.

I would suggest instead that you write the audio data to a file. Every time a client connects, you stream all the contents of the file to that client (You can open the file, skip to the end, and only stream new content if you want). You will want a new thread for each client, to do this.

If you are hoping to build something like Skype audio in Java, then this is a bit more complicated than just using TCP. TCP is a way to get data from A to B, reliably. With audio, you normally want it to get from A to B, but in real time. If you lose a packet of data in the process, you don't want to go back and retransmit it, because then you introduce delay to the call. The alternative to TCP, and probably more suited for your scenario, is UDP. It sends single packets, and does not guarantee they will arrive in order, or even at all. But it doesn't stop and wait for lost packets.

Andrew Williamson
  • 7,241
  • 2
  • 34
  • 56
  • Thank you.... Checking the line `int count = myTargetDataLine.read(buffer, 0, buffer.length);` I can to use a clone to copy to something `buffer.clone()` ... the problem is... I need to gain access to myServerPool Executers... to know the quantity are active and to create a array of ByteArrayOutputStream something like `myByteArrayOutStream[0] or myByteArrayOutStream[3]` ... – QA_Col Feb 18 '16 at 21:28
  • The idea of an executor is that once you pass it a task, it takes ownership, and you are not responsible for the task anymore. So the task should contain everything it needs in order to run, before you pass it off. Try giving your tasks the stream in their constructors. – Andrew Williamson Feb 18 '16 at 21:35
  • Sorry, but still I looking for a solution, maybe `ExecutorService myServerPool = Executors.newFixedThreadPool(4);` is not ideal object to be used, and an ArrayList of Threads instead... in this manner I have quantity and take each thread.... – QA_Col Feb 19 '16 at 00:17
  • I agree. You need one thread for each client that connects; a fixed thread pool cannot change the number of threads it is running after it has been created. The first step would be to replace the `myServerPool.execute(...)` with `Thread t = new Thread(...); t.start()`. – Andrew Williamson Feb 19 '16 at 16:31
  • Even so, Threads take a runnable as well. The idea of a runnable is that it contains everything it needs in order to run, before you pass it off. So you still need the `runnWorkerListener` constructor to take myByteArrayOutStream as a parameter. – Andrew Williamson Feb 19 '16 at 16:33