天天看點

實時語音通信

1.語音采集:用戶端程式,調用音頻驅動,實時采集”麥克風(mic)”的語音資料,儲存到記憶體中。

2. 語音傳輸:将記憶體中語音資料,通過TCP/IP協定傳輸到伺服器端。

3. 語音播放:伺服器接收音頻資料,并實時播放。

4. 設計可操作圖形界面

5. 作為可選的擴充功能1,實作端與端之間的雙向通信。

ps:服務端界面顯示了本地的IP位址。

用戶端和服務的都有儲存音頻檔案輸入框

1。服務端代碼:

import java.awt.BorderLayout;

import java.awt.Font;

import java.awt.GridLayout;

import java.awt.event.ActionEvent;

import java.awt.event.ActionListener;

import java.io.File;

import java.net.InetAddress;

import java.net.ServerSocket;

import java.net.Socket;

import java.net.UnknownHostException;

import javax.swing.JButton;

import javax.swing.JFrame;

import javax.swing.JLabel;

import javax.swing.JOptionPane;

import javax.swing.JPanel;

import javax.swing.JTextField;

public class Server extends JFrame implements ActionListener {

private    static String path;//接收檔案的路徑

private    static String savepath;//儲存檔案的路徑

        JPanel jp1, jp2, jp3,jp4;

        JLabel jl1 = null;

        JButton captureBtn, stopBtn, playBtn, saveBtn,sendBtn,setButton;

      //連接配接資訊和錄音資訊

        JLabel linkLabel=null;

        JLabel rdLabel=null;

        JLabel ipLabel=null;

        //路徑資訊

        JTextField  repath,svpath;

        //定義初始音頻類

       audioUtils server=null;

       //擷取本地IP

       InetAddress ia=null;

       Socket s=null;

     // 構造函數

        public  Server() throws UnknownHostException {

            // 元件初始化

            jp1 = new JPanel();

            jp2 = new JPanel();

            jp3 = new JPanel();

            jp4=new JPanel();

            //文本框初始化

              repath=new JTextField("輸入接收錄音檔案儲存的路徑");

               svpath=new JTextField("輸入要儲存的錄音檔案路徑");

            //定義連接配接和錄音提示

             linkLabel=new JLabel("未連接配接");

             rdLabel=new JLabel("");

             ipLabel=new JLabel("本地IP:"+ia.getLocalHost().getHostAddress());

             // 定義字型

            Font myFont = new Font("宋體", Font.BOLD, 30);

            jl1 = new JLabel("實時通信系統服務端");

            jl1.setFont(myFont);

            captureBtn = new JButton("開始錄音");

            // 對開始錄音按鈕進行注冊監聽

            captureBtn.addActionListener(this);

            captureBtn.setActionCommand("captureBtn");

            // 對停止錄音進行注冊監聽

            stopBtn = new JButton("停止錄音");

            stopBtn.addActionListener(this);

            stopBtn.setActionCommand("stopBtn");

            // 對播放錄音進行注冊監聽

            playBtn = new JButton("播放錄音");

            playBtn.addActionListener(this);

            playBtn.setActionCommand("playBtn");

            // 對儲存錄音進行注冊監聽

            saveBtn = new JButton("儲存錄音");

            saveBtn.addActionListener(this);

            saveBtn.setActionCommand("saveBtn");

            //對發送錄音進行注冊監聽

            sendBtn=new JButton("發送錄音");

            sendBtn.addActionListener(this);

            sendBtn.setActionCommand("sendBtn");

            //對設定ip,路徑等監聽

            setButton=new JButton("儲存設定");

            setButton.addActionListener(this);

            setButton.setActionCommand("setButton");

            this.add(jp1, BorderLayout.NORTH);

            this.add(jp2, BorderLayout.CENTER);

            this.add(jp3, BorderLayout.SOUTH);

            this.add(jp4,BorderLayout.NORTH);

            jp3.setLayout(null);

            jp3.setLayout(new GridLayout(1, 4, 10, 10));

            jp2.add(rdLabel);

            jp2.add(linkLabel);

            jp2.add(ipLabel);

            jp3.add(captureBtn);

            jp3.add(stopBtn);

            jp3.add(playBtn);

            jp3.add(saveBtn);

            jp3.add(sendBtn);

            jp4.add(svpath);

            jp4.add(repath);

            jp4.add(setButton);

            // 設定按鈕的屬性

            this.captureBtn.setEnabled(false);

            this.stopBtn.setEnabled(false);

            this.playBtn.setEnabled(false);

            this.saveBtn.setEnabled(false);

            this.sendBtn.setEnabled(false);

            // 設定視窗的屬性

            this.setSize(700, 500);

            this.setTitle("服務端");

            this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

            this.setLocationRelativeTo(null);

            this.setVisible(true);

            try {

                server=new audioUtils();

                //等待連接配接

                ServerSocket ss=new ServerSocket(8888);

                //阻塞方法,一直等待用戶端接入

                while(true){

                //監聽連接配接

                     s=ss.accept();

                    JOptionPane.showMessageDialog(null, "連接配接成功....");

                    System.out.println("已經連接配接");

                    linkLabel.setText("已連接配接:");

                    //開啟一個接收檔案的線程

                    server.recied(s, new File(path));

            }

            }

            catch (Exception e) {

            e.printStackTrace();

            linkLabel.setText("未連接配接:");

            }

        }

        //事件

        public void actionPerformed(ActionEvent e) {

            if (e.getActionCommand().equals("captureBtn")) {

                // 點選開始錄音按鈕後的動作

                // 停止按鈕可以啟動

                captureBtn.setEnabled(false);

                stopBtn.setEnabled(true);

                playBtn.setEnabled(false);

                saveBtn.setEnabled(false);

                sendBtn.setEnabled(false);

                // 調用錄音的方法

                capture();

                rdLabel.setText("正在錄音..");

            } else if (e.getActionCommand().equals("stopBtn")) {

                // 點選停止錄音按鈕的動作

                captureBtn.setEnabled(true);

                stopBtn.setEnabled(false);

                playBtn.setEnabled(true);

                saveBtn.setEnabled(true);

                if(s!=null)

                    sendBtn.setEnabled(true);    

                // 調用停止錄音的方法

                stop();

                rdLabel.setText("完成錄音..");

                }

             else if (e.getActionCommand().equals("playBtn")) {

                // 調用播放錄音的方法

                play();

            } else if (e.getActionCommand().equals("saveBtn")) {

                // 調用儲存錄音的方法

                rdLabel.setText("儲存錄音...");

                save();

            }else if(e.getActionCommand().equals("sendBtn")){

                //調用發送錄音的方法

                rdLabel.setText("發送錄音");

                send();

            }else if(e.getActionCommand().equals("setButton")){

                 path=repath.getText().trim();

                 savepath=svpath.getText().trim();

                 if(new File(savepath).isDirectory())

                 {

                     savepath+="/"+System.currentTimeMillis()+".mp3";

                     this.captureBtn.setEnabled(true);

                 }else{

                     svpath.setText("檔案路徑不存在!");

                     return ;

                 }

                 if(new File(path).isDirectory())

                 {

                     path+="/recied.mp3";

                 }else{

                     repath.setText("檔案路徑不存在!");

                     return ;

                 }

                this.setButton.setEnabled(false);

                 JOptionPane.showMessageDialog(null, "設定成功");

            }

}

        //開始錄音

        public void capture()        //錄音代碼

        {

              server.capture();

        }

        // 停止錄音

        public void stop() {

           server.stop();

        }

        // 播放錄音

        public void play(){

        server.play();

        }

        // 儲存錄音

        public void save() {

            // 取得錄音輸入流

    server.save(new File(savepath));

        }

    //發送錄音到用戶端(不儲存到本地檔案的發送)

        public void send()

        {

        server.send();

        }

    public static void main(String []args){

        try {

            Server ss=new Server();

        } catch (UnknownHostException e) {

            // TODO 自動生成的 catch 塊

            e.printStackTrace();

        }

    }

}

2.用戶端代碼:

import javax.swing.*;

import java.awt.BorderLayout;

import java.awt.Font;

import java.awt.GridLayout;

import java.awt.event.*;

import java.io.*;

import java.net.Socket;

import java.net.UnknownHostException;

import java.util.regex.Matcher;

import java.util.regex.Pattern;

public class Client extends JFrame implements ActionListener {

private    static String IP;//服務端的IP位址

private    static int port=8888;//端口号

private    static String path;//接收檔案的路徑

private    static String savepath;//儲存檔案的路徑

    //定義音頻類

    audioUtils client=null;

    // 定義所需要的元件

    JPanel jp1, jp2, jp3,jp4;

    JLabel jl1 = null;

    JButton captureBtn, stopBtn, playBtn, saveBtn,sendBtn,linkBtn,delinkBtn,setButton;

    JTextField  iptxt,repath,svpath;

    JLabel linkLabel=null;

    JLabel rdLabel=null;

    private Socket s;

    // 構造函數

    public  Client() {

        //音頻類初始化

       client=new audioUtils();

       //文本框初始化

       iptxt=new JTextField("輸入要連接配接的IP位址");

       repath=new JTextField("輸入接收錄音檔案儲存的路徑");

       svpath=new JTextField("輸入要儲存的錄音檔案路徑");

        // 元件初始化

        jp1 = new JPanel();

        jp2 = new JPanel();

        jp3 = new JPanel();

        jp4=new JPanel();

        //定義連接配接和錄音提示

         linkLabel=new JLabel("未連接配接");

         rdLabel=new JLabel("");

        // 定義字型

        Font myFont = new Font("宋體", Font.BOLD, 30);

        jl1 = new JLabel("實時通信系統用戶端");

        jl1.setFont(myFont);

        captureBtn = new JButton("開始錄音");

        // 對開始錄音按鈕進行注冊監聽

        captureBtn.addActionListener(this);

        captureBtn.setActionCommand("captureBtn");

        // 對停止錄音進行注冊監聽

        stopBtn = new JButton("停止錄音");

        stopBtn.addActionListener(this);

        stopBtn.setActionCommand("stopBtn");

        // 對播放錄音進行注冊監聽

        playBtn = new JButton("播放錄音");

        playBtn.addActionListener(this);

        playBtn.setActionCommand("playBtn");

        // 對儲存錄音進行注冊監聽

        saveBtn = new JButton("儲存錄音");

        saveBtn.addActionListener(this);

        saveBtn.setActionCommand("saveBtn");

        //對發送錄音進行注冊監聽

        sendBtn=new JButton("發送錄音");

        sendBtn.addActionListener(this);

        sendBtn.setActionCommand("sendBtn");

        //對連接配接錄音進行注冊監聽

        linkBtn=new JButton("連接配接");

        linkBtn.addActionListener(this);

        linkBtn.setActionCommand("linkBtn");

        //對斷開連接配接進行注冊監聽

        delinkBtn=new JButton("斷開連接配接");

        delinkBtn.addActionListener(this);

        delinkBtn.setActionCommand("delinkBtn");

        //對設定ip,路徑等監聽

        setButton=new JButton("儲存設定");

        setButton.addActionListener(this);

        setButton.setActionCommand("setButton");

        this.add(jp1, BorderLayout.NORTH);

        this.add(jp2, BorderLayout.CENTER);

        this.add(jp3, BorderLayout.SOUTH);

        this.add(jp4,BorderLayout.NORTH);

        jp3.setLayout(null);

        jp3.setLayout(new GridLayout(1, 4, 10, 10));

        jp4.add(iptxt);

        jp4.add(svpath);

        jp4.add(repath);

        jp4.add(setButton);

        jp2.add(rdLabel);

        jp2.add(linkBtn);

        jp2.add(delinkBtn);

        jp2.add(linkLabel);

        jp3.add(captureBtn);

        jp3.add(stopBtn);

        jp3.add(playBtn);

        jp3.add(saveBtn);

        jp3.add(sendBtn);

        // 設定按鈕的屬性

        this.linkBtn.setEnabled(false);

        this.delinkBtn.setEnabled(false);

        this.captureBtn.setEnabled(false);

        this.stopBtn.setEnabled(false);

        this.playBtn.setEnabled(false);

        this.saveBtn.setEnabled(false);

        this.sendBtn.setEnabled(false);

        this.setButton.setEnabled(true);

        // 設定視窗的屬性

        this.setSize(700, 500);

        this.setTitle("用戶端");

        this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        this.setLocationRelativeTo(null);

        this.setVisible(true);

    }

    public void actionPerformed(ActionEvent e) {

        if (e.getActionCommand().equals("captureBtn")) {

            // 點選開始錄音按鈕後的動作

            // 停止按鈕可以啟動

            captureBtn.setEnabled(false);

            stopBtn.setEnabled(true);

            playBtn.setEnabled(false);

            saveBtn.setEnabled(false);

            sendBtn.setEnabled(false);

            // 調用錄音的方法

            capture();

            rdLabel.setText("正在錄音..");

        } else if (e.getActionCommand().equals("stopBtn")) {

            // 點選停止錄音按鈕的動作

            captureBtn.setEnabled(true);

            stopBtn.setEnabled(false);

            playBtn.setEnabled(true);

            saveBtn.setEnabled(true);

            if(!linkBtn.isEnabled()){

                sendBtn.setEnabled(true);

            }

            // 調用停止錄音的方法

            stop();

            rdLabel.setText("完成錄音..");

        } else if (e.getActionCommand().equals("playBtn")) {

            // 調用播放錄音的方法

            play();

        } else if (e.getActionCommand().equals("saveBtn")) {

            // 調用儲存錄音的方法

            rdLabel.setText("儲存錄音..");

            save();

        }else if(e.getActionCommand().equals("sendBtn")){

            rdLabel.setText("發送錄音..");

            send();

        }

        else if(e.getActionCommand().equals("linkBtn")){

            linkBtn.setEnabled(false);

            delinkBtn.setEnabled(true);

            if(saveBtn.isEnabled())

            sendBtn.setEnabled(true);

            link();

            if(s.isConnected())

            linkLabel.setText("已連接配接:");

        }

        else if(e.getActionCommand().equals("delinkBtn")){

            delinkBtn.setEnabled(false);

            linkBtn.setEnabled(true);

            sendBtn.setEnabled(false);

            delink();

            linkLabel.setText("未連接配接:");

        }else if(e.getActionCommand().equals("setButton")){

            //校驗ip位址

            Pattern p = Pattern.compile("^((25[0-5]|2[0-4]\\d|[1]{1}\\d{1}\\d{1}|[1-9]{1}\\d{1}|\\d{1})($|(?!\\.$)\\.)){4}$");

            Matcher m = p.matcher(iptxt.getText());

            boolean b = m.matches();

            if(!b){

                iptxt.setText("IP輸入不合法");

                return ;

            }

             IP=iptxt.getText().trim();

             path=repath.getText().trim();

             savepath=svpath.getText().trim();

             if(new File(savepath).isDirectory())

             {

                 savepath+="/"+System.currentTimeMillis()+".mp3";

                 this.captureBtn.setEnabled(true);

             }else{

                 svpath.setText("檔案路徑不存在!");

                 return ;

             }

             if(new File(path).isDirectory())

             {

                 path+="/recied.mp3";

             }else{

                 repath.setText("檔案路徑不存在!");

                 return;

             }

             this.linkBtn.setEnabled(true);

            this.setButton.setEnabled(false);

             JOptionPane.showMessageDialog(null, "設定成功");

        }

    }

    //連接配接到服務端

    public void link()

    {

        //初始化一個套接字

         try {

                s=new Socket(IP,port);

            //開啟一個接收檔案的線程

            client.recied(s, new File(path));

        } catch (UnknownHostException e) {

            System.out.println("連接配接失敗");

        } catch (IOException e) {

            // TODO 自動生成的 catch 塊

            e.printStackTrace();

        }

    }

    public void delink() {

         if(s.isClosed())System.out.println("目前并無連接配接");

        try {

            s.close();

        } catch (IOException e) {

            // TODO 自動生成的 catch 塊

            e.printStackTrace();

        }

    }

//錄音

    public void capture(){

        client.capture();

    }

    // 停止錄音

public void stop(){

    client.stop();

}

//播放錄音(預設播放剛剛完成的錄音)

public void play(){

    client.play();

}

    // 儲存錄音

public void save(){

    client.save(new File(savepath));

}

//發送錄音到服務端(不儲存到本地的發送)

    public void send(){

        client.send();

    }

//

    public static void main(String[] args) {

        // 創造一個執行個體

        Client tc=new Client();

    }

}

3。音頻工具類

//音頻工具類。需要執行個體化。

import java.io.BufferedInputStream;

import java.io.ByteArrayInputStream;

import java.io.ByteArrayOutputStream;

import java.io.File;

import java.io.IOException;

import java.io.InputStream;

import java.net.Socket;

import java.net.UnknownHostException;

import javax.sound.sampled.*;

import javax.swing.JOptionPane;

class audioUtils

{

        // 定義錄音格式

    private    AudioFormat af = null;

        // 定義目标資料行,可以從中讀取音頻資料,該 TargetDataLine 接口提供從目标資料行的緩沖區讀取所捕獲資料的方法。

    private    TargetDataLine td = null;

        // 定義源資料行,源資料行是可以寫入資料的資料行。它充當其混頻器的源。應用程式将音頻位元組寫入源資料行,這樣可處理位元組緩沖并将它們傳遞給混頻器。

    private    SourceDataLine sd = null;

        // 定義位元組數組輸入輸出流

    private    ByteArrayInputStream bais = null;

    private    ByteArrayOutputStream baos = null;

        // 定義音頻輸入流

    private    AudioInputStream ais = null;

        // 定義停止錄音的标志,來控制錄音線程的運作

    private    Boolean stopflag = false;

    private    Socket s=null;

    //預設的AudioFormat

    private AudioFormat.Encoding encoding = AudioFormat.Encoding.

            PCM_SIGNED ;

    private     float rate = 16000f;

    private         int sampleSize = 16;

    private         String signedString = "signed";

    private         boolean bigEndian = true;

    private         int channels = 2;

    public  void recied(Socket s,File file)

    {

            //開啟一個接收檔案的線程

            recied r=new recied(s,file);

            Thread t1=new Thread(r);

             t1.start();

    }

    public void stop() {

        stopflag = true;

        //之前的源音頻資料流要關了

        if(td!=null)

            {

            td.close();

            }

    }

        public void play(){

            Thread t1=new Thread(new play(ais));

            t1.start();

        }

        public void play(AudioInputStream ais){

            Thread t1=new Thread(new play(ais));

            t1.start();

        }

        public void save(File file) {

            // 取得錄音輸入流

            af = getAudioFormat();

            byte audioData[] = baos.toByteArray();

            bais = new ByteArrayInputStream(audioData);

            ais = new AudioInputStream(bais, af, audioData.length

                    / af.getFrameSize());

            // 寫入檔案

            try {

                if (!file.exists()) {// 如果檔案不存在,則建立該檔案

                    file.createNewFile();

                }

                AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);

            } catch (Exception e) {

                e.printStackTrace();

            } finally {

                // 關閉流

                try {

                    if (bais != null) {

                        bais.close();

                    }

                    if (ais != null) {

                        ais.close();

                    }

                } catch (Exception e) {

                    e.printStackTrace();

                }

            }

        }

        public  void capture()        //錄音代碼

        {

            try {

                af = getAudioFormat();

                DataLine.Info info = new DataLine.Info(TargetDataLine.class,af);

                td = (TargetDataLine)(AudioSystem.getLine(info));

                td.open(af);

                td.start();

                Record record = new Record();

                Thread t1 = new Thread(record);

                t1.start();

            } catch (LineUnavailableException ex) {

                ex.printStackTrace();

                return;

            }

        }

        public void send()

        {

            Thread t1=new Thread(new Send());

            t1.start();

            if(s.isClosed()){

                throw new RuntimeException();

            }

        }

        // 錄音類,因為要用到MyRecord類中的變量,是以将其做成内部類

        class Record implements Runnable    // 錄音線程    

        {

            byte bts[] = new byte[10000];

            public void run() {    

                baos = new ByteArrayOutputStream();        

                try {

                    System.out.println("用戶端正在錄音...");

                    stopflag = false;

                    while(stopflag != true)

                    {

                        int cnt = td.read(bts, 0, bts.length);

                        if(cnt > 0)

                        {

                            baos.write(bts, 0, cnt);

                        }

                    }

                    af = getAudioFormat();

                    byte audioData[] = baos.toByteArray();

                    bais = new ByteArrayInputStream(audioData);

                    ais = new AudioInputStream(bais, af, audioData.length

                            / af.getFrameSize());

                       //檢視資料

                    System.out.println("長度:"+ais.getFrameLength()+"最大"+ais.available());

                } catch (Exception e) {

                    e.printStackTrace();

                }finally{

                    try {

                        if(baos != null)

                        {

                            baos.close();

                        }    

                        if(bais!=null){

                            bais.close();

                        }

                   } catch (IOException e) {

                        e.printStackTrace();

                    }finally{

                        td.drain();

                        td.close();

                    }

                }

            }

        }

        // 設定AudioFormat的參數

        public AudioFormat getAudioFormat()    //錄音格式

        {

            return new AudioFormat(encoding, rate, sampleSize, channels,(sampleSize / 8) * channels, rate, bigEndian);

        }

        public void setAudioFormat

(AudioFormat.Encoding encoding,float rate,int sampleSize,String signedString,boolean bigEndian,int channels)

        {

            this.encoding = encoding;

                    this.rate = 16000f;

                    this. sampleSize = 16;

                    this.signedString = "signed";

                this. bigEndian = true;

                    this. channels = 2;

        }

        //播放線程類

        class play implements Runnable{

          private AudioInputStream ais;

            public play(AudioInputStream ais){

              this.ais=ais;

          }

            @Override

            public void run() {

                // TODO 自動生成的方法存根

                playAudio(ais);

            }

            //接收一個音頻流

            public  void playAudio(AudioInputStream ais)

            {

                try{

                    AudioFormat baseFormat=ais.getFormat();

                    DataLine.Info info=new DataLine.Info(SourceDataLine.class, baseFormat);

                    SourceDataLine line=(SourceDataLine)AudioSystem.getLine(info);

                    System.out.println("正在播放錄音");

                    line.open(baseFormat); 

                    line.start();

                    int BUFFER_SIZE=4000*4;

                    int intBytes=0;

                    int outBytes;

                    byte[] audioData=new byte[BUFFER_SIZE];

                    while(intBytes!=-1)

                    {

                        intBytes=ais.read(audioData, 0, BUFFER_SIZE);

                        if(intBytes>=0)

                            outBytes=line.write(audioData, 0, intBytes);                

                    }

                }catch(Exception e)

                {

                    e.printStackTrace();

                }

                finally{

                    try {

                        ais.close();

                    } catch (IOException e) {

                        // TODO 自動生成的 catch 塊

                        System.out.println("關流失敗");

                    }

                }

            }

        }

        //發送檔案的線程類(不用儲存到本地檔案直接發送)

        class Send implements Runnable{

            public void run()

            {

                send();

             }

            private  void send(){

                 try {

                        af = getAudioFormat();

                        byte audioData[] = baos.toByteArray();

                        bais = new ByteArrayInputStream(audioData);

                        ais = new AudioInputStream(bais, af, audioData.length

                                / af.getFrameSize());

                        if(s!=null){

                        //将輸入流寫入服務端的輸出流

                            s.getOutputStream().flush();

                        AudioSystem.write(ais, AudioFileFormat.Type.WAVE, s.getOutputStream());

                        }

                        System.out.println("發送到服務端");

                        ais.close();

                 }

                 catch (UnknownHostException e) {

                    // TODO 自動生成的 catch 塊

                    e.printStackTrace();

                } catch (IOException e) {

                    // TODO 自動生成的 catch 塊

                    e.printStackTrace();

                }

            }

        }

        //收語音的線程,并播放的類

            class recied implements Runnable{

                InputStream in=null;

                File file=null;

                public recied(Socket socket,File file){

                    s=socket;

                    this.file=file;

                }

                @Override

                public void run() {

                    // TODO 自動生成的方法存根

                    try{

                        while(true)

                        {

                        if (!file.exists()) {// 如果檔案不存在,則建立該目錄

                            file.createNewFile();

                        }

                        //獲得用戶端的讀取流(阻塞)

                        in=s.getInputStream();

                        //這個網絡流不允許讀寫頭來回移動,也就不允許mark/reset機制需要buffer包起來。

                        BufferedInputStream bufin=new BufferedInputStream(in);    

                    //擷取到用戶端傳過來的輸入流,并轉化為錄音輸入流

                        ais = AudioSystem.getAudioInputStream(bufin);

                    //寫入本地檔案.

                     AudioSystem.write(ais, AudioFileFormat.Type.WAVE, file);

                     System.out.println("收到錄音..");

                     JOptionPane.showMessageDialog(null, "收到錄音....");

                      AudioInputStream aui=AudioSystem.getAudioInputStream(file);

                     //播放收到的聲音

                     play(aui);

                        }

                    }catch(Exception e){

                        e.getStackTrace();

                    }

                }

            }

}

繼續閱讀