【问题标题】:JAVA (sending audio streaming One Server Four Clients in the same machine)JAVA(发送音频流一服务器四客户端在同一台机器)
【发布时间】:2016-05-31 05:33:53
【问题描述】:

我之前问过:https://stackoverflow.com/questions/35344535/dcom-alternative-for-java-sending-audio-streaming-in-the-same-machine

我想从我的麦克风捕获音频并使用一台服务器发送到客户端(0 或 4)...

PD:我正在检查这个问题:Sending audio stream over TCP, UnsupportedAudioFileException,但面向的是一台服务器和一台客户端解决方案。 其他问题:Java - Broadcast voice over Java sockets Streaming audio from microphone with Java

我正在考虑使用 TCP(服务器/客户端模型),但服务器和 4 个客户端将接收数据(音频流),我不知道是否可以实施这种替代方案(我担心端口管理)....

这里是我的初步(它仍然不工作,因为我有疑问,我在想如何解决我的顾虑)

变量:

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

现在我很头疼

  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());
  }

问题:

(合并在runnAudioCapture代码中查找帮助)

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?

现在是工作线程--

  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();
      }
    }
  }

问题:

(合并到 runnWorkerListener 代码中以查找帮助)

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

我的怀疑与以下内容有关: 一个线程专用于音频捕获 一个线程专用于接收客户端(1、2、3 或 4),使用 Pool 并创建线程工作者(一个线程工作者与“远程”客户端通信)

我不知道将 Capturer 线程 Capturer 与每个 Worker 线程同步的句柄...

谢谢...

【问题讨论】:

    标签: java multithreading audio tcp client-server


    【解决方案1】:

    不幸的是,在 Java 中,流只能一次由一个人使用。您有一个流 myByteArrayOutStream,并且您想在 4 个 TCP 连接之间共享它。

    我建议您将音频数据写入文件。每次客户端连接时,您都会将文件的所有内容流式传输到该客户端(您可以打开文件,跳到最后,并且只在需要时才流式传输新内容)。您需要为每个客户端创建一个新线程来执行此操作。

    如果您希望在 Java 中构建类似 Skype 音频的东西,那么这比仅使用 TCP 稍微复杂一些。 TCP 是一种从 A 到 B 获取数据的方式,可靠。对于音频,您通常希望它从 A 到 B,但是是实时的。如果你在这个过程中丢失了一个数据包,你不想回去重新传输它,因为这样你就会给调用带来延迟。 TCP 的替代方案(可能更适合您的方案)是 UDP。它发送单个数据包,并且不保证它们会按顺序到达,甚至根本不保证。但它不会停下来等待丢失的数据包。

    【讨论】:

    • 谢谢...。检查int count = myTargetDataLine.read(buffer, 0, buffer.length); 行我可以使用克隆复制到buffer.clone() 的东西...问题是...我需要访问myServerPool Executers ...要知道数量是活跃的并创建一个 ByteArrayOutputStream 数组,例如myByteArrayOutStream[0] or myByteArrayOutStream[3] ...
    • 执行者的想法是,一旦您将任务传递给它,它就会获得所有权,并且您不再对任务负责。因此,在您传递任务之前,该任务应该包含运行所需的一切。尝试在其构造函数中为您的任务提供流。
    • 对不起,但我仍然在寻找解决方案,也许ExecutorService myServerPool = Executors.newFixedThreadPool(4); 不是理想的使用对象,而是一个 ArrayList 线程......以这种方式我有数量并占用每个线程。 ...
    • 我同意。每个连接的客户端都需要一个线程;固定线程池在创建后无法更改它正在运行的线程数。第一步是将myServerPool.execute(...) 替换为Thread t = new Thread(...); t.start()
    • 即便如此,线程也需要一个可运行对象。可运行对象的想法是,它包含运行所需的一切,然后再将其传递出去。所以你还是需要runnWorkerListener构造函数把myByteArrayOutStream作为参数。
    猜你喜欢
    • 2014-06-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-11-22
    相关资源
    最近更新 更多