【问题标题】:Pc audio to android = noisePC 音频到 android = 噪音
【发布时间】:2018-08-26 19:54:09
【问题描述】:

我的一个项目有问题。 该项目是一个语音聊天,您应该能够在其中跨设备相互交谈。 当 2 个 pc 客户端正在通话时,该项目运行良好。 当 pc 客户端正在通话并且 android 设备获取数据时,它充满了噪音。我能隐约听到在说什么。 有人知道我可以做些什么来过滤掉噪音吗?

所有代码都在这里

PC 客户端:

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

}

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

}

安卓

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

据我所知,PC 设置与 Android 设置 AudioFormat 和 AudioTrack 匹配。

【问题讨论】:

  • .setSampleRate(41000) 是错字吗?您已经为44100.setSampleRate(sampleRate) 定义了一个常量,我不知道这是否是单声道声音的有效采样率。我认为这就是 cd 立体声采样率(红皮书)。 Double checked。来自维基百科链接:音频 CD 可以表示高达 22.05 kHz 的频率,即 44.1 kHz 采样率的奈奎斯特频率。
  • 是的,这是一个错字。不管我设置什么采样率,结果都是一样的

标签: java android audio server


【解决方案1】:

所以我知道这已经很晚了,但我遇到了同样的问题。

AudioFormat af = new AudioFormat(44100, 16, 1, true, true);

在音频格式中,最后一个值必须为 false。 bigEndian Flag 它改变了流中的字节顺序。

因此,只需将最后一个值更改为 false,您的代码就会运行。

AudioFormat af = new AudioFormat(44100, 16, 1, true, false);

【讨论】:

  • 非常感谢。打破一切的总是一件小事:)
  • 乐于助人:D
猜你喜欢
  • 2013-04-08
  • 2014-10-25
  • 2021-05-02
  • 2012-04-27
  • 2010-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多