2012-07-24 39 views
3

我正在嘗試編寫一個Java語音聊天應用程序,並且已經實現了回聲功能,但是當嘗試連接多個客戶端時,我被卡住了。我知道你不能迭代套接字並將數據發送給所有連接的人,而不會混淆數據。 (我試過了,聽起來不像它應該如何)。我不太確定該怎麼做,而且我正在使用一個非常簡單的字節緩衝回顯服務器作爲服務器(我想要執行混合)。我還有一個客戶端,可以接收麥克風輸入,將其發送到服務器,從服務器獲取數據,並從揚聲器播放數據。Java語音聊天 - Mixdown傳入數據單輸出

注意:客戶端由2個類(Program和SoundReceiver)組成。我正在使用javax.sound.sampled庫。

回聲服務器: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路電話一樣)。

+0

個人(我知道我不是唯一的一個),我往往懶得點擊這樣的鏈接。在你的問題中插入你的代碼通常是一個好主意。如果你覺得將所有代碼內聯太多,創建一個[SSCCE](http://sscce.org),如果可能的話,總是一個好主意。 – Jeffrey 2012-07-24 02:29:33

+0

有沒有一種更簡單的方法來發布代碼比在每行之前製作4個空格? – zgillis 2012-07-24 02:50:48

+0

看起來這與套接字沒有多大關係,但與聲音處理有關。 – 2012-07-24 03:01:45

回答

1

設置serverSocket的限制可能會有所幫助,例如新的ServerSocket(3000,101);像積壓或隊列長度..

1

這是此行:

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

在服務器側,我認爲將數據發送回由於客戶機其中有一個回聲。我認爲你應該省略這條線。

0

我認爲你需要在服務器端創建一個檢查。它就像是如果sendAll從EChoThread被調用,它有連接實例只是將其傳遞給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){} 
     } 
    }