⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 captureplaybackclient.java

📁 java语言编写的语音聊天室程序
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
   * createAudioInputStream(file, false);
   */
  public class Playback
      implements Runnable {

    SourceDataLine line;
    Thread thread;

    public void start() {
      errStr = null;
      thread = new Thread(this);
      thread.setName("Playback");
      thread.start();
    }

    public void stop() {
      thread = null;
    }

    private void shutDown(String message) {
      if ( (errStr = message) != null) {
        System.err.println(errStr);
        samplingGraph.repaint();
      }
      if (thread != null) {
        thread = null;
        samplingGraph.stop();
        captB.setEnabled(true);
        pausB.setEnabled(false);
        playB.setText("Play");
      }
    }

    //实现播放线程
    public void run() {

      // 如果audioInputStream由文件载入,我们将重载播放的文件reload the file if loaded by file
      if (file != null) {
        createAudioInputStream(file, false); //false表示不用更新audioInputStream的格式
      }

      // audioInputStream不能为空,make sure we have something to play
      if (audioInputStream == null) {
        shutDown("No loaded audio to play back");
        return;
      }
      // 复位流媒体,reset to the beginnning of the stream
      try {
        audioInputStream.reset();
      }
      catch (Exception e) {
        shutDown("Unable to reset the stream\n" + e);
        return;
      }

      //得到期望的格式信息!get an AudioInputStream of the desired format for playback
      AudioFormat format = formatControls.getFormat();
      // !!!将输入的流对象audioInputStream,格式化后得到一个标准的流对象playbackInputStream
      AudioInputStream playbackInputStream = AudioSystem.getAudioInputStream(
          format, audioInputStream);

      if (playbackInputStream == null) {
        shutDown("Unable to convert stream of format " + audioInputStream +
                 " to format " + format);
        return;
      }
      // 为我们的line定义需要的属性;define the required attributes for our line,
      // 确定一个兼容的line格式;and make sure a compatible line is supported.

      DataLine.Info info = new DataLine.Info(SourceDataLine.class,
                                             format);
      //判断系统是否支持匹配这个Line.Info的line;
      if (!AudioSystem.isLineSupported(info)) {
        shutDown("Line matching " + info + " not supported.");
        return;
      }

      //从AudioSystem中得到期望的格式line,类型化为SourceDataLine以用于读取;get and open the source data line for playback.
      try {
        line = (SourceDataLine) AudioSystem.getLine(info);
        //causing the line to acquire any required system resources and become operational
        line.open(format, bufSize);
      }
      catch (LineUnavailableException ex) {
        shutDown("Unable to open the line: " + ex);
        return;
      }
      //对line的操作次序:open();getBufferSize();start();write(data,0,num);drain();
      /**
       * line的最大BufferSize是16384;一个frame大小由AudioFormat决定;frame大小乘上(buffer里的frame数量)=这里line实际用的bufferData大小
       */
      // 重放捕获的声音数据 play back the captured audio data
      //**frame大小由AudioFormat决定,这里为4字节长;
       int frameSizeInBytes = format.getFrameSize();
      //For a source data line, this is maximum size of the buffer to which data can be written.  For a target data line, it is maximum size of the buffer from which data can be read.
      int bufferLengthInFrames = line.getBufferSize() / 8;
      //bufferLengthInBytes为8192----bufferLengthInFrames为2048
      int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
      //在线程里,data被不断初始化!
      byte[] data = new byte[bufferLengthInBytes];
      int numBytesRead = 0;

      // Allows a line to engage in data I/O.(the line must be flushed or stoped)
      line.start();
      //playbackInputStream->data[]->dataline
      while (thread != null) {
        try {
          //取出playbackInputStream并写到字节流data[byte]中!返回事实读取的量,跳出。
          if ( (numBytesRead = playbackInputStream.read(data)) == -1) {
            break;
          }
          int numBytesRemaining = numBytesRead;
          while (numBytesRemaining > 0) {
            //line.write(data, 0, numBytesRemaining)返回已写入line的数据数量
            numBytesRemaining -= line.write(data, 0, numBytesRemaining);
          }
        }
        catch (Exception e) {
          shutDown("Error during playback: " + e);
          break;
        }
      }
      // 向line写完字节流,结束when reached the end of the stream,let the data play out, then
      // stop and close the line.
      if (thread != null) {
        //排出Drains queued data from the line by continuing data I/O until line's internal buffer has been emptied.
        line.drain();
        //line.flush()---Flushes queued data from the line.
      }
      line.stop();
      line.close();
      line = null;
      shutDown(null);
    }
  } // End class Playback

  /**
   * 从输入渠道中捕获数据,并写到输出流中;Reads data from the input channel and writes to the output stream
   */
  class Capture
      implements Runnable {

    TargetDataLine line;
    Thread thread;

    public void start() {
      errStr = null;
      thread = new Thread(this);
      //thread是有名字的;
      thread.setName("Capture");
      thread.start();
    }

    public void stop() {
      thread = null;
    }

    private void shutDown(String message) {
      if ( (errStr = message) != null && thread != null) {
        thread = null;
        samplingGraph.stop();
        loadB.setEnabled(true);
        playB.setEnabled(true);
        pausB.setEnabled(false);
        auB.setEnabled(true);
        aiffB.setEnabled(true);
        waveB.setEnabled(true);
        captB.setText("Record");
        connB.setText("连接");
        System.err.println(errStr);
        samplingGraph.repaint();
      }
    }

    public void run() {

      duration = 0;
      //将audioInputStream置空!
      audioInputStream = null;

      // define the required attributes for our line,
      // and make sure a compatible line is supported.

      AudioFormat format = formatControls.getFormat();
      DataLine.Info info = new DataLine.Info(TargetDataLine.class,
                                             format);

      if (!AudioSystem.isLineSupported(info)) {
        shutDown("Line matching " + info + " not supported.");
        return;
      }

      // 获得并打开目标dataline来捕获get and open the target data line for capture.

      try {
        line = (TargetDataLine) AudioSystem.getLine(info);
        //这里将获得声音!!
        line.open(format, line.getBufferSize());
      }
      catch (LineUnavailableException ex) {
        shutDown("Unable to open the line: " + ex);
        return;
      }
      catch (SecurityException ex) {
        shutDown(ex.toString());
//        JavaSound.showInfoDialog();
        return;
      }
      catch (Exception ex) {
        shutDown(ex.toString());
        return;
      }

      // line.read(data[])——播放
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      int frameSizeInBytes = format.getFrameSize();
      int bufferLengthInFrames = line.getBufferSize() / 8;
      int bufferLengthInBytes = bufferLengthInFrames * frameSizeInBytes;
      byte[] data = new byte[bufferLengthInBytes];
      int numBytesRead;

      line.start();

      while (thread != null) {
        if ( (numBytesRead = line.read(data, 0, bufferLengthInBytes)) == -1) {
          break;
        }
        out.write(data, 0, numBytesRead);
      }

      // we reached the end of the stream.  stop and close the line.
      line.stop();
      line.close();
      line = null;

      // 停止和关闭输出流stop and close the output stream
      try {
        out.flush();
        out.close();
      }
      catch (IOException ex) {
        ex.printStackTrace();
      }

      // !!!将输入流载入到audioInputStream对象中!load bytes into the audio input stream for playback

      byte audioBytes[] = out.toByteArray();
      ByteArrayInputStream bais = new ByteArrayInputStream(audioBytes);
      audioInputStream = new AudioInputStream(bais, format,
                                              audioBytes.length /
                                              frameSizeInBytes);

      long milliseconds = (long) ( (audioInputStream.getFrameLength() * 1000) /
                                  format.getFrameRate());
      duration = milliseconds / 1000.0;

      try {
        audioInputStream.reset();
      }
      catch (Exception ex) {
        ex.printStackTrace();
        return;
      }
//在捕获的线程里调用画图!hlf   //kehu---duankai2---huahua
      samplingGraph.createWaveForm(audioBytes);
    }
  } // End class Capture

  /**
   * 画波形图.//hlf!!
   */
  class SamplingGraph
      extends JPanel
      implements Runnable {

    private Thread thread;
    private Font font10 = new Font("serif", Font.PLAIN, 10);
    private Font font12 = new Font("serif", Font.PLAIN, 12);

    //深色底面
    Color jfcBlue = new Color(204, 204, 255);
    //粉色画当前位置线
    Color pink = new Color(255, 175, 175);

    public SamplingGraph() {
      setBackground(new Color(20, 20, 20));
    }

    //画波形图!
    public void createWaveForm(byte[] audioBytes) {

      lines.removeAllElements(); // clear the old vector

      AudioFormat format = audioInputStream.getFormat();

      if (audioBytes == null) {
        try {
          audioBytes = new byte[ (int) (audioInputStream.getFrameLength()
                                        * format.getFrameSize())];
          audioInputStream.read(audioBytes);
        }
        catch (Exception ex) {
          reportStatus(ex.toString());
          return;
        }
      }
      Dimension d = getSize();
      int w = d.width;
      int h = d.height - 15;
      int[] audioData = null;
      if (format.getSampleSizeInBits() == 16) {
        int nlengthInSamples = audioBytes.length / 2;
        audioData = new int[nlengthInSamples];
        if (format.isBigEndian()) {
          for (int i = 0; i < nlengthInSamples; i++) {
            /* First byte is MSB (high order) */
            int MSB = (int) audioBytes[2 * i];
            /* Second byte is LSB (low order) */
            int LSB = (int) audioBytes[2 * i + 1];
            audioData[i] = MSB << 8 | (255 & LSB);
          }
        }
        else {
          for (int i = 0; i < nlengthInSamples; i++) {
            /* First byte is LSB (low order) */
            int LSB = (int) audioBytes[2 * i];
            /* Second byte is MSB (high order) */
            int MSB = (int) audioBytes[2 * i + 1];
            audioData[i] = MSB << 8 | (255 & LSB);
          }
        }
      }
      else if (format.getSampleSizeInBits() == 8) {
        int nlengthInSamples = audioBytes.length;
        audioData = new int[nlengthInSamples];
        if (format.getEncoding().toString().startsWith("PCM_SIGN")) {
          for (int i = 0; i < audioBytes.length; i++) {
            audioData[i] = audioBytes[i];
          }
        }
        else {

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -