I have a problem with a project of mine. The project is a voice chat, where you should be able to talk to each other across devices. The project works fine when 2 pc clients is talking. When a pc client is talking and the android device gets the data, it is filled with noise. I can faintly hear what is being said. Do anybody know what i can do to filter out the noise?
All the code is here
PC Client:
package test; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; import javax.sound.sampled.AudioFormat; import javax.sound.sampled.AudioSystem; import javax.sound.sampled.DataLine; import javax.sound.sampled.LineUnavailableException; import javax.sound.sampled.SourceDataLine; import javax.sound.sampled.TargetDataLine; public class Client extends javax.swing.JFrame { private Socket socket; private ObjectInputStream dis; private ObjectOutputStream dos; private ServerHandler sh = new ServerHandler(); private SourceDataLine speaker = null; //speaker private TargetDataLine mic = null; private MicThread micThread; private Thread speakerThread; private boolean keepPlaying = true; public Client() { initComponents(); } class ServerHandler extends Thread { @Override public void run () { try { socket = new Socket(server.getText(), new Integer(port.getText())); dos = new ObjectOutputStream(socket.getOutputStream()); dis = new ObjectInputStream(socket.getInputStream()); login((int) number.getValue()); try { byte[] bytes; DataPacket dp; while ((dp = (DataPacket) dis.readObject()) != null) { if (speaker == null || dp == null) { return; } bytes = dp.getBytes(); speaker.write(bytes, 0, bytes.length); } } catch (IOException ex) { ex.printStackTrace(); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } public void login (int uid) { Login l = new Login(uid); try { dos.writeObject(l); } catch (Exception ex) { ex.printStackTrace(); } } public void send (byte[] bytes) { if (dos == null) { return; } try { DataPacket dp = new DataPacket((int) calling.getValue(), bytes.length, bytes); dos.writeObject(dp); } catch (IOException ex) { ex.printStackTrace(); } } public void connect () { } public void disconnect () { mic.stop(); try { if (dis != null) { dis.close(); } if (dos != null) { dos.close(); } if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } class MicThread extends Thread { public MicThread () { try { AudioFormat af = new AudioFormat(44100, 16, 1, true, true); DataLine.Info info = new DataLine.Info(TargetDataLine.class, null); mic = (TargetDataLine) (AudioSystem.getLine(info)); mic.open(af); mic.start(); } catch (LineUnavailableException ex) { ex.printStackTrace(); } } @Override public void run () { for (;;) { if (mic.available() >= 7072) { byte[] buff = new byte[7072]; while (mic.available() >= 7072) { mic.read(buff, 0, buff.length); } long tot = 0; for (int i = 0; i < buff.length; i++) { tot += Math.abs(buff[i]); } tot *= 2.5; tot /= buff.length; if (tot == 0) { } else { sh.send(buff); } } else { try { Thread.sleep(10); } catch (InterruptedException ex) { ex.printStackTrace(); } } } } } /** * This method is called from within the constructor to initialize the form. * WARNING: Do NOT modify this code. The content of this method is always * regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // <editor-fold defaultstate="collapsed" desc="Generated Code"> private void initComponents() { jPanel1 = new javax.swing.JPanel(); connect = new javax.swing.JButton(); port = new javax.swing.JTextField(); server = new javax.swing.JTextField(); jLabel1 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel(); hangupButton = new javax.swing.JButton(); jPanel2 = new javax.swing.JPanel(); jLabel3 = new javax.swing.JLabel(); number = new javax.swing.JSpinner(); callButton = new javax.swing.JButton(); calling = new javax.swing.JSpinner(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); connect.setText("Connect"); connect.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { connectActionPerformed(evt); } }); port.setText("2222"); server.setText("localhost"); jLabel1.setText("Server"); jLabel2.setText("Port"); javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1); jPanel1.setLayout(jPanel1Layout); jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addComponent(jLabel1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 200, Short.MAX_VALUE) .addComponent(server, javax.swing.GroupLayout.Alignment.LEADING)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(port, javax.swing.GroupLayout.DEFAULT_SIZE, 88, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(connect)) .addGroup(jPanel1Layout.createSequentialGroup() .addComponent(jLabel2) .addGap(0, 0, Short.MAX_VALUE)))) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() .addContainerGap() .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel1) .addComponent(jLabel2)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(port) .addComponent(connect, javax.swing.GroupLayout.DEFAULT_SIZE, 37, Short.MAX_VALUE) .addComponent(server, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) ); hangupButton.setText("Hangup"); hangupButton.setEnabled(false); hangupButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { hangupButtonActionPerformed(evt); } }); jLabel3.setText("Number"); javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2); jPanel2.setLayout(jPanel2Layout); jPanel2Layout.setHorizontalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(jLabel3) .addGap(0, 0, Short.MAX_VALUE)) .addComponent(number, javax.swing.GroupLayout.Alignment.TRAILING) ); jPanel2Layout.setVerticalGroup( jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel2Layout.createSequentialGroup() .addComponent(jLabel3) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(number, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) ); callButton.setText("Call"); callButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { callButtonActionPerformed(evt); } }); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(calling) .addComponent(jPanel2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(hangupButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(callButton, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) .addContainerGap()) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createSequentialGroup() .addContainerGap() .addComponent(jPanel2, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jPanel1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(calling, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(3, 3, 3) .addComponent(callButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(hangupButton) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) ); pack(); }// </editor-fold> private void connectActionPerformed(java.awt.event.ActionEvent evt) { sh.start(); hangupButton.setEnabled(true); speakerThread = new Thread(new Runnable() { @Override public void run() { try { //open channel to sound card //AudioFormat af = new AudioFormat(11025f, 8, 1, true, true); //AudioFormat af = new AudioFormat(33075f, 16, 1, true, true); AudioFormat af = new AudioFormat(44100f, 16, 1, true, true); DataLine.Info info = new DataLine.Info(SourceDataLine.class, af); speaker = (SourceDataLine) AudioSystem.getLine(info); speaker.open(af); speaker.start(); //sound card ready } catch (Exception e) { //sound card error or connection error, stop e.printStackTrace(); if (speaker != null) { speaker.close(); } } } }); speakerThread.start(); } private void hangupButtonActionPerformed(java.awt.event.ActionEvent evt) { sh.disconnect(); hangupButton.setEnabled(false); System.exit(0); } private void callButtonActionPerformed(java.awt.event.ActionEvent evt) { micThread = new MicThread(); micThread.start(); } /** * @param args the command line arguments */ public static void main(String args[]) { /* Set the Nimbus look and feel */ //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) "> /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel. * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html */ try { for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { if ("Nimbus".equals(info.getName())) { javax.swing.UIManager.setLookAndFeel(info.getClassName()); break; } } } catch (ClassNotFoundException ex) { java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (InstantiationException ex) { java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (IllegalAccessException ex) { java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } catch (javax.swing.UnsupportedLookAndFeelException ex) { java.util.logging.Logger.getLogger(Client.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); } //</editor-fold> //</editor-fold> /* Create and display the form */ java.awt.EventQueue.invokeLater(new Runnable() { public void run() { new Client().setVisible(true); } }); } // Variables declaration - do not modify private javax.swing.JButton callButton; private javax.swing.JSpinner calling; private javax.swing.JButton connect; private javax.swing.JButton hangupButton; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel2; private javax.swing.JSpinner number; private javax.swing.JTextField port; private javax.swing.JTextField server; // End of variables declaration }
DataPacket.java:
package test; import java.io.Serializable; public class DataPacket implements Serializable { private int to = 0; private int sizeInBytes = 1200; private byte[] bytes = null; public DataPacket (int to, int sizeInBytes, byte[] bytes) { this.to = to; this.sizeInBytes = sizeInBytes; this.bytes = bytes; } public int getTo () { return to; } public int getSizeInBytes () { return sizeInBytes; } public byte[] getBytes () { return bytes; } }
Login.java:
package test; import java.io.Serializable; public class Login implements Serializable { private int number = 0; public Login (int number) { this.number = number; } public int getNumber () { return number; } }
Server.java:
package test; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.ServerSocket; import java.net.Socket; import java.util.HashMap; import java.util.Iterator; import java.util.Set; public class Server { private HashMap<Integer, ClientThread> connected = new HashMap<>(); private int port = 2222; private boolean keepGoing = true; private void stop () { keepGoing = false; try { new Socket("localhost", port); } catch(Exception e) { } } private void start () { keepGoing = true; try { ServerSocket serverSocket = new ServerSocket(port); while (keepGoing) { Socket socket = serverSocket.accept(); if (!keepGoing) { break; } ClientThread t = new ClientThread(socket); t.start(); } try { serverSocket.close(); Set<Integer> set = connected.keySet(); Iterator<Integer> it = set.iterator(); while (it.hasNext()) { int i = it.next(); ClientThread t = connected.get(i); t.close(); } } catch (Exception e) { } } catch (IOException e) { } } class ClientThread extends Thread { private Socket socket; private ObjectInputStream dis; private ObjectOutputStream dos; private int userID; // The user id of the loggedin user public ClientThread(Socket socket) { this.socket = socket; try { this.dis = new ObjectInputStream(socket.getInputStream()); this.dos = new ObjectOutputStream(socket.getOutputStream()); } catch (IOException e) { } } public void sendVoice (DataPacket dp) { try { dos.writeObject(dp); } catch (IOException ex) { ex.printStackTrace(); } } @Override public void run () { boolean keepGoing = true; while (keepGoing) { try { if (dis == null) { keepGoing = false; break; } Object obj = dis.readObject(); System.out.println(obj); if (obj instanceof DataPacket) { DataPacket dp = (DataPacket) obj; int to = dp.getTo(); ClientThread ct = connected.get(to); if (ct != null) { ct.sendVoice(dp); } } else if (obj instanceof Login) { Login l = (Login) obj; userID = l.getNumber(); connected.put(userID, this); } } catch (IOException e) { keepGoing = false; e.printStackTrace(); } catch (ClassNotFoundException ex) { keepGoing = false; ex.printStackTrace(); } } close(); } public void close () { try { if (dos != null) {dos.close();} if (dis != null) {dis.close();} if (socket != null) {socket.close();} } catch (IOException e) { } closeThread(userID); } } public void closeThread (int updater) { ClientThread ct = connected.get(updater); if (ct != null) { ct.interrupt(); } connected.remove(updater); } public static void main(String[] args) { Server s = new Server(); s.start(); } }
ANDROID
MainActivity.java
package test.test; import android.media.AudioAttributes; import android.media.AudioFormat; import android.media.AudioTrack; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.EditText; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.net.Socket; import java.nio.file.Files; import test.DataPacket; import test.Login; public class MainActivity extends AppCompatActivity { private Socket socket; private ObjectInputStream dis; private ObjectOutputStream dos; private ServerHandler sh = new ServerHandler(); private AudioTrack speaker = null; //private TargetDataLine mic = null; //private MicThread micThread; private Thread speakerThread; private boolean keepPlaying = true; private EditText number; private EditText server; private EditText port; private EditText calling; class ServerHandler extends Thread { @Override public void run () { try { socket = new Socket(server.getText().toString(), new Integer(port.getText().toString())); dos = new ObjectOutputStream(socket.getOutputStream()); dis = new ObjectInputStream(socket.getInputStream()); login(new Integer(number.getText().toString())); try { byte[] bytes; DataPacket dp; while ((dp = (DataPacket) dis.readObject()) != null) { if (speaker == null || dp == null) { return; } bytes = dp.getBytes(); speaker.write(bytes, 0, bytes.length); } } catch (IOException ex) { ex.printStackTrace(); } catch (ClassNotFoundException ex) { ex.printStackTrace(); } } catch (IOException e) { e.printStackTrace(); } } public void login (int uid) { Login l = new Login(uid); try { dos.writeObject(l); } catch (Exception ex) { ex.printStackTrace(); } } public void send (byte[] bytes) { if (dos == null) { return; } try { DataPacket dp = new DataPacket(new Integer(calling.getText().toString()), bytes.length, bytes); dos.writeObject(dp); } catch (IOException ex) { ex.printStackTrace(); } } public void connect () { } public void disconnect () { //mic.stop(); try { if (dis != null) { dis.close(); } if (dos != null) { dos.close(); } if (socket != null) { socket.close(); } } catch (IOException e) { e.printStackTrace(); } } } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); number = (EditText) findViewById(R.id.number); server = (EditText) findViewById(R.id.server); port = (EditText) findViewById(R.id.port); calling = (EditText) findViewById(R.id.calling); Button connect = (Button) findViewById(R.id.connect); Button callButton = (Button) findViewById(R.id.callButton); Button hangupButton = (Button) findViewById(R.id.hangupButton); connect.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { sh.start(); } }); callButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { } }); hangupButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { finish(); } }); sh = new ServerHandler(); int sampleRate = 44100; int bufferSize = AudioTrack.getMinBufferSize(sampleRate, AudioFormat.CHANNEL_OUT_MONO, AudioFormat.ENCODING_PCM_16BIT); speaker = new AudioTrack(new AudioAttributes.Builder() .setUsage(AudioAttributes.USAGE_MEDIA) .setContentType(AudioAttributes.CONTENT_TYPE_MUSIC) .build(), new AudioFormat.Builder() .setEncoding(AudioFormat.ENCODING_PCM_16BIT) .setSampleRate(41000) .setChannelMask(AudioFormat.CHANNEL_OUT_MONO) .build(), bufferSize, AudioTrack.MODE_STREAM, 0); speaker.play(); } }
As far as i can see, the PC settings matches the Android settings AudioFormat and AudioTrack.
Advertisement
Answer
So I know this is pretty late but I encountered the same problem.
AudioFormat af = new AudioFormat(44100, 16, 1, true, true);
In the audio format the last value needs to be false. The bigEndian Flag it changes the byte order in the stream.
So just change the last value to false and your code will work.
AudioFormat af = new AudioFormat(44100, 16, 1, true, false);