Java语音聊天 - 混合单输出的传入数据

时间:2012-07-24 02:16:33

标签: java sockets audio javax.sound.sampled

我正在尝试编写Java语音聊天应用程序,并且已经实现了回声功能,但在尝试连接多个客户端时,我陷入困境。我知道你不能遍历套接字并将数据发送给所有连接的人而不会混淆数据。 (我试过,听起来不像它应该如何)。我不太清楚该怎么做,我使用一个非常简单的字节缓冲的echo服务器作为服务器(我想在其中执行混音)。我还有一个客户端,它接收麦克风输入,将其发送到服务器,从服务器获取数据,并从扬声器中播放数据。

注意:客户端由2个类(Program和SoundReceiver)组成。我正在使用javax.sound.sampled库。

Echo Server:http://pastebin.com/c9KiaTpJ

import java.net.*;
import java.io.*;
import java.util.*;

public class Echo
{
    public static void main(String[] args) throws Exception
    {
        ServerSocket serverSocket = new ServerSocket(3000);
        while(true){Thread echoThread = new Thread(new EchoThread(serverSocket.accept()));
                    echoThread.start();}
    }
}

class EchoThread implements Runnable
{
    public static Collection<Socket> sockets = new ArrayList<Socket>();
    Socket connection = null;
    DataInputStream dataIn = null;
    DataOutputStream dataOut = null;

    public EchoThread(Socket conn) throws Exception
    {
        connection = conn;
        dataIn = new DataInputStream(connection.getInputStream());
        dataOut = new DataOutputStream(connection.getOutputStream());
        sockets.add(connection);
    }

    public void run()
    {
        int bytesRead = 0;
        byte[] inBytes = new byte[1];
        while(bytesRead != -1)
        {
            try{bytesRead = dataIn.read(inBytes, 0, inBytes.length);}catch (IOException e){}
            if(bytesRead >= 0)
            {
                sendToAll(inBytes, bytesRead);
            }
        }
        sockets.remove(connection);
    }

    public static void sendToAll(byte[] byteArray, int q)
    {
        Iterator<Socket> sockIt = sockets.iterator();
        while(sockIt.hasNext())
        {
            Socket temp = sockIt.next();
            DataOutputStream tempOut = null;
            try
            {
                tempOut = new DataOutputStream(temp.getOutputStream());
            } catch (IOException e1)
            {
                // TODO Auto-generated catch block
                e1.printStackTrace();
            }
            try{tempOut.write(byteArray, 0, q);}catch (IOException e){}
        }
    }
}

客户端程序类:http://pastebin.com/v24CYwXE

import java.io.DataOutputStream;
import java.net.*;
import javax.sound.sampled.*;

public class Program
{
    public static void main(String[] args) throws Exception
    {
        AudioFormat af = new AudioFormat(8000.0f,8,1,true,false);
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, af);
        TargetDataLine microphone = (TargetDataLine)AudioSystem.getLine(info);
        microphone.open(af);
        Socket conn = new Socket("localhost",3000);
        microphone.start();
        DataOutputStream dos = new DataOutputStream(conn.getOutputStream());
        int bytesRead = 0;
        byte[] soundData = new byte[1];
        Thread inThread = new Thread(new SoundReceiver(conn));
        inThread.start();
        while(bytesRead != -1)
        {
            bytesRead = microphone.read(soundData, 0, soundData.length);
            if(bytesRead >= 0)
            {
                dos.write(soundData, 0, bytesRead);
            }
        }
        System.out.println("IT IS DONE.");
    }
}

客户端SoundReceiver类:http://pastebin.com/2tt0Jucv

import java.net.*;
import java.io.*;

import javax.sound.sampled.*;

public class SoundReceiver implements Runnable
{
    Socket connection = null;
    DataInputStream soundIn = null;
    SourceDataLine inSpeaker = null;

    public SoundReceiver(Socket conn) throws Exception
    {
        connection = conn;
        soundIn = new DataInputStream(connection.getInputStream());
        AudioFormat af = new AudioFormat(8000.0f,8,1,true,false);
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, af);
        inSpeaker = (SourceDataLine)AudioSystem.getLine(info);
        inSpeaker.open(af);
    }

    public void run()
    {
        int bytesRead = 0;
        byte[] inSound = new byte[1];
        inSpeaker.start();
        while(bytesRead != -1)
        {
            try{bytesRead = soundIn.read(inSound, 0, inSound.length);} catch (Exception e){}
            if(bytesRead >= 0)
            {
                inSpeaker.write(inSound, 0, bytesRead);
            }
        }
    }
}

基本上,我想将所有传入的字节合并为一个字节数组,同时保持每个人的语音都满(就像一个3方电话)。

3 个答案:

答案 0 :(得分:1)

设置serverSocket的限制可能会有所帮助,例如new ServerSocket(3000,101);积压或队列长度......

答案 1 :(得分:1)

这一行:

try
{
    tempOut.write(byteArray, 0, q);
}
catch (IOException e){
} 

在服务器端,我认为将数据发送回客户端,因为存在回声。我想你应该省略这条线。

答案 2 :(得分:0)

我认为你需要在服务器端创建一个检查。就像从EChoThread调用sendAll那个连接实例只是将它传递给sendAll并且如果它们相同则将sockIt与连接进行比较那么这就是发送日期的同一个套接字而且不需要向它发送数据我只是跳过它然后移动到下一个插座。

应在服务器端进行以下更改:

     public void run()
{
    int bytesRead = 0;
    byte[] inBytes = new byte[1];
    while(bytesRead != -1)
    {
        try{bytesRead = dataIn.read(inBytes, 0, inBytes.length);}catch (IOException e)       {}
        if(bytesRead >= 0)
        {
            sendToAll(connection, inBytes, bytesRead);
        }
    }
    sockets.remove(connection);
}


public static void sendToAll(Socket connection, byte[] byteArray, int q)
{
    Iterator<socket> sockIt = sockets.iterator();
    while(sockIt.hasNext())
    {
        Socket temp = sockIt.next();
        if(connection == temp){
            continue;
        }
        DataOutputStream tempOut = null;
        try
        {
            tempOut = new DataOutputStream(temp.getOutputStream());
        } catch (IOException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try{tempOut.write(byteArray, 0, q);}catch (IOException e){}
      }
  }




 public void run()
{
    int bytesRead = 0;
    byte[] inBytes = new byte[1];
    while(bytesRead != -1)
    {
        try{bytesRead = dataIn.read(inBytes, 0, inBytes.length);}catch (IOException e)       {}
        if(bytesRead >= 0)
        {
            sendToAll(connection, inBytes, bytesRead);
        }
    }
    sockets.remove(connection);
}


public static void sendToAll(Socket connection, byte[] byteArray, int q)
{
    Iterator<socket> sockIt = sockets.iterator();
    while(sockIt.hasNext())
    {
        Socket temp = sockIt.next();
        if(connection == temp){
            continue;
        }
        DataOutputStream tempOut = null;
        try
        {
            tempOut = new DataOutputStream(temp.getOutputStream());
        } catch (IOException e1)
        {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }
        try{tempOut.write(byteArray, 0, q);}catch (IOException e){}
      }
  }