├── README.md ├── VoiceChat_Client ├── .gitignore ├── build.xml ├── manifest.mf ├── nbproject │ ├── build-impl.xml │ ├── genfiles.properties │ ├── private │ │ ├── config.properties │ │ ├── private.properties │ │ └── private.xml │ ├── project.properties │ └── project.xml └── src │ ├── AudioChannel.java │ ├── Client.java │ ├── GUI.form │ ├── GUI.java │ └── MicThread.java ├── VoiceChat_Comm ├── .gitignore ├── build.xml ├── manifest.mf ├── nbproject │ ├── build-impl.xml │ ├── genfiles.properties │ ├── private │ │ ├── config.properties │ │ ├── private.properties │ │ └── private.xml │ ├── project.properties │ └── project.xml └── src │ ├── ErrorMessage.java │ ├── Message.java │ ├── SoundPacket.java │ └── Utils.java └── VoiceChat_Server ├── .gitignore ├── build.xml ├── lib ├── cling-core-1.0.5.jar ├── cling-support-1.0.5.jar └── teleal-common-1.0.13.jar ├── manifest.mf ├── nbproject ├── build-impl.xml ├── genfiles.properties ├── private │ ├── config.properties │ ├── private.properties │ └── private.xml ├── project.properties └── project.xml └── src ├── ClientConnection.java ├── GUI.form ├── GUI.java ├── Log.java └── Server.java /README.md: -------------------------------------------------------------------------------- 1 | # VoiceChat 2 | 3 | VoiceChat is a simple VoIP application written in Java that supports uPnP, conversations with multiple users and basic compression with comfort noise. 4 | 5 | ## Download 6 | [Download from my site](http://downloads.fdossena.com/geth.php?r=voicechat-bin) (Requires [Java](http://java.com)) 7 | 8 | ## Usage 9 | If you want to play with the code, just import the projects into Netbeans 10 | 11 | ## Compatibility 12 | Multiplaform, Java SE 7 13 | 14 | ## Screenshots 15 | ![Screenshot](http://fdossena.com/voip/server1.png) 16 | ![Screenshot](http://fdossena.com/voip/client1.png) 17 | 18 | ## License 19 | Copyright (C) 2015 Federico Dossena 20 | 21 | This program is free software: you can redistribute it and/or modify 22 | it under the terms of the GNU General Public License as published by 23 | the Free Software Foundation, either version 3 of the License, or 24 | (at your option) any later version. 25 | 26 | This program is distributed in the hope that it will be useful, 27 | but WITHOUT ANY WARRANTY; without even the implied warranty of 28 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 29 | GNU General Public License for more details. 30 | 31 | You should have received a copy of the GNU General Public License 32 | along with this program. If not, see . 33 | -------------------------------------------------------------------------------- /VoiceChat_Client/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /VoiceChat_Client/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Builds, tests, and runs the project VoiceChat_Client. 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /VoiceChat_Client/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | X-COMMENT: Main-Class will be added automatically by build 3 | 4 | -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/genfiles.properties: -------------------------------------------------------------------------------- 1 | build.xml.data.CRC32=12915718 2 | build.xml.script.CRC32=5d70ffe9 3 | build.xml.stylesheet.CRC32=8064a381@1.68.1.46 4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. 5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. 6 | nbproject/build-impl.xml.data.CRC32=12915718 7 | nbproject/build-impl.xml.script.CRC32=e90885cd 8 | nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46 9 | -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/private/config.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Client/nbproject/private/config.properties -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/private/private.properties: -------------------------------------------------------------------------------- 1 | compile.on.save=true 2 | do.depend=false 3 | do.jar=true 4 | javac.debug=true 5 | javadoc.preview=true 6 | user.properties.file=C:\\Users\\dosse\\AppData\\Roaming\\NetBeans\\7.4\\build.properties 7 | -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/private/private.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | file:/C:/Users/dosse/Documents/NetBeansProjects/VoiceChat_Client/src/GUI.java 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/project.properties: -------------------------------------------------------------------------------- 1 | annotation.processing.enabled=true 2 | annotation.processing.enabled.in.editor=false 3 | annotation.processing.processors.list= 4 | annotation.processing.run.all.processors=true 5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output 6 | application.title=VoiceChat_Client 7 | application.vendor=dosse 8 | build.classes.dir=${build.dir}/classes 9 | build.classes.excludes=**/*.java,**/*.form 10 | # This directory is removed when the project is cleaned: 11 | build.dir=build 12 | build.generated.dir=${build.dir}/generated 13 | build.generated.sources.dir=${build.dir}/generated-sources 14 | # Only compile against the classpath explicitly listed here: 15 | build.sysclasspath=ignore 16 | build.test.classes.dir=${build.dir}/test/classes 17 | build.test.results.dir=${build.dir}/test/results 18 | # Uncomment to specify the preferred debugger connection transport: 19 | #debug.transport=dt_socket 20 | debug.classpath=\ 21 | ${run.classpath} 22 | debug.test.classpath=\ 23 | ${run.test.classpath} 24 | # This directory is removed when the project is cleaned: 25 | dist.dir=dist 26 | dist.jar=${dist.dir}/VoiceChat_Client.jar 27 | dist.javadoc.dir=${dist.dir}/javadoc 28 | endorsed.classpath= 29 | excludes= 30 | includes=** 31 | jar.archive.disabled=${jnlp.enabled} 32 | jar.compress=false 33 | jar.index=${jnlp.enabled} 34 | javac.classpath=\ 35 | ${reference.VoiceChat_Comm.jar} 36 | # Space-separated list of extra javac options 37 | javac.compilerargs= 38 | javac.deprecation=false 39 | javac.processorpath=\ 40 | ${javac.classpath} 41 | javac.source=1.7 42 | javac.target=1.7 43 | javac.test.classpath=\ 44 | ${javac.classpath}:\ 45 | ${build.classes.dir} 46 | javac.test.processorpath=\ 47 | ${javac.test.classpath} 48 | javadoc.additionalparam= 49 | javadoc.author=false 50 | javadoc.encoding=${source.encoding} 51 | javadoc.noindex=false 52 | javadoc.nonavbar=false 53 | javadoc.notree=false 54 | javadoc.private=false 55 | javadoc.splitindex=true 56 | javadoc.use=true 57 | javadoc.version=false 58 | javadoc.windowtitle= 59 | jnlp.codebase.type=no.codebase 60 | jnlp.descriptor=application 61 | jnlp.enabled=false 62 | jnlp.mixed.code=default 63 | jnlp.offline-allowed=false 64 | jnlp.signed=false 65 | jnlp.signing= 66 | jnlp.signing.alias= 67 | jnlp.signing.keystore= 68 | main.class=GUI 69 | manifest.file=manifest.mf 70 | meta.inf.dir=${src.dir}/META-INF 71 | mkdist.disabled=false 72 | platform.active=default_platform 73 | project.VoiceChat_Comm=../VoiceChat_Comm 74 | reference.VoiceChat_Comm.jar=${project.VoiceChat_Comm}/dist/VoiceChat_Comm.jar 75 | run.classpath=\ 76 | ${javac.classpath}:\ 77 | ${build.classes.dir} 78 | # Space-separated list of JVM arguments used when running the project 79 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value 80 | # or test-sys-prop.name=value to set system properties for unit tests): 81 | run.jvmargs= 82 | run.test.classpath=\ 83 | ${javac.test.classpath}:\ 84 | ${build.test.classes.dir} 85 | source.encoding=UTF-8 86 | src.dir=src 87 | test.src.dir=test 88 | -------------------------------------------------------------------------------- /VoiceChat_Client/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.java.j2seproject 4 | 5 | 6 | VoiceChat_Client 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | VoiceChat_Comm 17 | jar 18 | 19 | jar 20 | clean 21 | jar 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /VoiceChat_Client/src/AudioChannel.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.ByteArrayInputStream; 3 | import java.io.ByteArrayOutputStream; 4 | import java.util.ArrayList; 5 | import java.util.zip.GZIPInputStream; 6 | import javax.sound.sampled.AudioFormat; 7 | import javax.sound.sampled.AudioSystem; 8 | import javax.sound.sampled.DataLine; 9 | import javax.sound.sampled.SourceDataLine; 10 | 11 | /* 12 | * To change this template, choose Tools | Templates and open the template in 13 | * the editor. 14 | */ 15 | /** 16 | * this thread plays the sound coming from one of the users that are connected 17 | * on the server. each user has its own AudioChannel. 18 | * 19 | * @author dosse 20 | */ 21 | public class AudioChannel extends Thread { 22 | 23 | private long chId; //an id unique for each user. generated by IP and port 24 | private ArrayList queue = new ArrayList(); //queue of messages to be played 25 | private int lastSoundPacketLen = SoundPacket.defaultDataLenght; 26 | private long lastPacketTime = System.nanoTime(); 27 | 28 | public boolean canKill() { //returns true if it's been a long time since last received packet 29 | if (System.nanoTime() - lastPacketTime > 5000000000L) { 30 | return true; //5 seconds with no data 31 | } else { 32 | return false; 33 | } 34 | } 35 | 36 | public void closeAndKill() { 37 | if (speaker != null) { 38 | speaker.close(); 39 | } 40 | stop(); 41 | } 42 | 43 | public AudioChannel(long chId) { 44 | this.chId = chId; 45 | } 46 | 47 | public long getChId() { 48 | return chId; 49 | } 50 | 51 | public void addToQueue(Message m) { //adds a message to the play queue 52 | queue.add(m); 53 | } 54 | private SourceDataLine speaker = null; //speaker 55 | 56 | @Override 57 | public void run() { 58 | try { 59 | //open channel to sound card 60 | AudioFormat af = SoundPacket.defaultFormat; 61 | DataLine.Info info = new DataLine.Info(SourceDataLine.class, af); 62 | speaker = (SourceDataLine) AudioSystem.getLine(info); 63 | speaker.open(af); 64 | speaker.start(); 65 | //sound card ready 66 | for (;;) { //this infinite cycle checks for new packets to be played in the queue, and plays them. to avoid busy wait, a sleep(10) is executed at the beginning of each iteration 67 | if (queue.isEmpty()) { //nothing to play, wait 68 | Utils.sleep(10); 69 | continue; 70 | } else {//we got something to play 71 | lastPacketTime = System.nanoTime(); 72 | Message in = queue.get(0); 73 | queue.remove(in); 74 | if (in.getData() instanceof SoundPacket) { //it's a sound packet, send it to sound card 75 | SoundPacket m = (SoundPacket) (in.getData()); 76 | if (m.getData() == null) {//sender skipped a packet, play comfort noise 77 | byte[] noise = new byte[lastSoundPacketLen]; 78 | for (int i = 0; i < noise.length; i++) { 79 | noise[i] = (byte) ((Math.random() * 3) - 1); 80 | } 81 | speaker.write(noise, 0, noise.length); 82 | } else { 83 | //decompress data 84 | GZIPInputStream gis = new GZIPInputStream(new ByteArrayInputStream(m.getData())); 85 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 86 | for (;;) { 87 | int b = gis.read(); 88 | if (b == -1) { 89 | break; 90 | } else { 91 | baos.write((byte) b); 92 | } 93 | } 94 | //play decompressed data 95 | byte[] toPlay=baos.toByteArray(); 96 | speaker.write(toPlay, 0, toPlay.length); 97 | lastSoundPacketLen = m.getData().length; 98 | } 99 | } else { //not a sound packet, trash 100 | continue; //invalid message 101 | } 102 | } 103 | } 104 | } catch (Exception e) { //sound card error or connection error, stop 105 | System.out.println("receiverThread " + chId + " error: " + e.toString()); 106 | if (speaker != null) { 107 | speaker.close(); 108 | } 109 | stop(); 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /VoiceChat_Client/src/Client.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.IOException; 3 | import java.io.ObjectInputStream; 4 | import java.io.ObjectOutputStream; 5 | import java.net.Socket; 6 | import java.net.UnknownHostException; 7 | import java.util.ArrayList; 8 | 9 | /* 10 | * To change this template, choose Tools | Templates and open the template in 11 | * the editor. 12 | */ 13 | /** 14 | * Connects to the server, then starts receiving messages. Creates 15 | * a MicThread that sends microphone data to the server, and creates an instance 16 | * of AudioThread for each user. 17 | * @author dosse 18 | */ 19 | public class Client extends Thread { 20 | 21 | private Socket s; 22 | private ArrayList chs = new ArrayList(); 23 | private MicThread st; 24 | 25 | public Client(String serverIp, int serverPort) throws UnknownHostException, IOException { 26 | s = new Socket(serverIp, serverPort); 27 | } 28 | 29 | @Override 30 | public void run() { 31 | try { 32 | ObjectInputStream fromServer = new ObjectInputStream(s.getInputStream()); //create object streams with the server 33 | ObjectOutputStream toServer = new ObjectOutputStream(s.getOutputStream()); 34 | try { 35 | Utils.sleep(100); //wait for the GUI microphone test to release the microphone 36 | st = new MicThread(toServer); //creates a MicThread that sends microphone data to the server 37 | st.start(); //starts the MicThread 38 | } catch (Exception e) { //error acquiring microphone. causes: no microphone or microphone busy 39 | System.out.println("mic unavailable " + e); 40 | } 41 | for (;;) { //this infinite cycle checks for new data from the server, then sends it to the correct AudioChannel. if needed, a new AudioChannel is created 42 | 43 | if (s.getInputStream().available() > 0) { //we got something from the server (workaround: used available method from InputStream instead of the one from ObjetInputStream because of a bug in the JRE) 44 | Message in = (Message) (fromServer.readObject()); //read message 45 | //decide which audio channel should get this message 46 | AudioChannel sendTo = null; 47 | for (AudioChannel ch : chs) { 48 | if (ch.getChId() == in.getChId()) { 49 | sendTo = ch; 50 | } 51 | } 52 | if (sendTo != null) { 53 | sendTo.addToQueue(in); 54 | } else { //new AudioChannel is needed 55 | AudioChannel ch = new AudioChannel(in.getChId()); 56 | ch.addToQueue(in); 57 | ch.start(); 58 | chs.add(ch); 59 | } 60 | }else{ //see if some channels need to be killed and kill them 61 | ArrayList killMe=new ArrayList(); 62 | for(AudioChannel c:chs) if(c.canKill()) killMe.add(c); 63 | for(AudioChannel c:killMe){c.closeAndKill(); chs.remove(c);} 64 | Utils.sleep(1); //avoid busy wait 65 | } 66 | } 67 | } catch (Exception e) { //connection error 68 | System.out.println("client err " + e.toString()); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /VoiceChat_Client/src/GUI.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 |
136 | -------------------------------------------------------------------------------- /VoiceChat_Client/src/GUI.java: -------------------------------------------------------------------------------- 1 | 2 | import javax.sound.sampled.AudioFormat; 3 | import javax.sound.sampled.AudioSystem; 4 | import javax.sound.sampled.DataLine; 5 | import javax.sound.sampled.TargetDataLine; 6 | import javax.swing.JOptionPane; 7 | 8 | /* 9 | * To change this template, choose Tools | Templates and open the template in 10 | * the editor. 11 | */ 12 | /** 13 | * 14 | * @author dosse 15 | */ 16 | public class GUI extends javax.swing.JFrame { 17 | private MicTester micTester; 18 | //this class is used to test the microphone. it manages the volume meter 19 | private class MicTester extends Thread{ 20 | private TargetDataLine mic = null; 21 | public MicTester() { 22 | 23 | } 24 | @Override 25 | public void run() { 26 | 27 | try { 28 | AudioFormat af = SoundPacket.defaultFormat; 29 | DataLine.Info info = new DataLine.Info(TargetDataLine.class, null); 30 | mic = (TargetDataLine) (AudioSystem.getLine(info)); 31 | mic.open(af); 32 | mic.start(); 33 | } catch (Exception e) { 34 | JOptionPane.showMessageDialog(rootPane,"Microphone not detected.\nPress OK to close this program", "Error",JOptionPane.ERROR_MESSAGE); 35 | System.exit(0); 36 | } 37 | for (;;) { 38 | Utils.sleep(10); 39 | if(mic.available()>0){ 40 | byte[] buff=new byte[SoundPacket.defaultDataLenght]; 41 | mic.read(buff,0,buff.length); 42 | long tot=0; 43 | for(int i=0;i//GEN-BEGIN:initComponents 71 | private void initComponents() { 72 | 73 | ip = new javax.swing.JTextField(); 74 | start = new javax.swing.JButton(); 75 | port = new javax.swing.JTextField(); 76 | jLabel1 = new javax.swing.JLabel(); 77 | jLabel3 = new javax.swing.JLabel(); 78 | micLev = new javax.swing.JProgressBar(); 79 | jLabel2 = new javax.swing.JLabel(); 80 | jLabel4 = new javax.swing.JLabel(); 81 | micVol = new javax.swing.JSlider(); 82 | 83 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 84 | setResizable(false); 85 | 86 | ip.setText("127.0.0.1"); 87 | 88 | start.setText("Connect"); 89 | start.addActionListener(new java.awt.event.ActionListener() { 90 | public void actionPerformed(java.awt.event.ActionEvent evt) { 91 | startActionPerformed(evt); 92 | } 93 | }); 94 | 95 | port.setText("1049"); 96 | 97 | jLabel1.setText("Server IP and port"); 98 | 99 | jLabel3.setText("Mic level"); 100 | 101 | jLabel2.setText("If the mic level doesn't move as you speak, the mic volume is too low"); 102 | 103 | jLabel4.setText("Mic volume"); 104 | 105 | micVol.setMaximum(300); 106 | micVol.setMinimum(50); 107 | micVol.setValue(100); 108 | micVol.addChangeListener(new javax.swing.event.ChangeListener() { 109 | public void stateChanged(javax.swing.event.ChangeEvent evt) { 110 | micVolStateChanged(evt); 111 | } 112 | }); 113 | 114 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 115 | getContentPane().setLayout(layout); 116 | layout.setHorizontalGroup( 117 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 118 | .addGroup(layout.createSequentialGroup() 119 | .addContainerGap() 120 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 121 | .addComponent(jLabel2, javax.swing.GroupLayout.DEFAULT_SIZE, 338, Short.MAX_VALUE) 122 | .addComponent(start, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 123 | .addGroup(layout.createSequentialGroup() 124 | .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 107, javax.swing.GroupLayout.PREFERRED_SIZE) 125 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 126 | .addComponent(ip) 127 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 128 | .addComponent(port, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE)) 129 | .addGroup(layout.createSequentialGroup() 130 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) 131 | .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 132 | .addComponent(jLabel3, javax.swing.GroupLayout.DEFAULT_SIZE, 63, Short.MAX_VALUE)) 133 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 134 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 135 | .addComponent(micLev, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 136 | .addComponent(micVol, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))) 137 | .addContainerGap()) 138 | ); 139 | layout.setVerticalGroup( 140 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 141 | .addGroup(layout.createSequentialGroup() 142 | .addContainerGap() 143 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 144 | .addComponent(ip, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 145 | .addComponent(port, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 146 | .addComponent(jLabel1)) 147 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 148 | .addComponent(start) 149 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 150 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 151 | .addComponent(jLabel3) 152 | .addComponent(micLev, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) 153 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 154 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) 155 | .addComponent(micVol, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 156 | .addComponent(jLabel4, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 157 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) 158 | .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 14, javax.swing.GroupLayout.PREFERRED_SIZE) 159 | .addContainerGap()) 160 | ); 161 | 162 | pack(); 163 | }// //GEN-END:initComponents 164 | 165 | private void startActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startActionPerformed 166 | try { 167 | new Client(ip.getText(), Integer.parseInt(port.getText())).start(); //connect to specified server at specified port 168 | } catch (Exception ex) { //connection failed 169 | JOptionPane.showMessageDialog(rootPane, ex,"Error",JOptionPane.ERROR_MESSAGE); 170 | return; 171 | } 172 | //connected, disable buttons 173 | micTester.close(); 174 | ip.setEnabled(false); 175 | port.setEnabled(false); 176 | start.setEnabled(false); 177 | micLev.setVisible(false); 178 | jLabel1.setEnabled(false); 179 | jLabel3.setVisible(false); 180 | micVol.setVisible(false); 181 | jLabel4.setVisible(false); 182 | jLabel2.setVisible(false); 183 | setSize(getWidth(),getHeight()-75); 184 | }//GEN-LAST:event_startActionPerformed 185 | 186 | private void micVolStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_micVolStateChanged 187 | MicThread.amplification=((double)(micVol.getValue()))/100.0; 188 | }//GEN-LAST:event_micVolStateChanged 189 | 190 | /** 191 | * @param args the command line arguments 192 | */ 193 | public static void main(String args[]) { 194 | /* 195 | * Set the Nimbus look and feel 196 | */ 197 | // 198 | /* 199 | * If Nimbus (introduced in Java SE 6) is not available, stay with the 200 | * default look and feel. For details see 201 | * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 202 | */ 203 | try { 204 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { 205 | if ("Nimbus".equals(info.getName())) { 206 | javax.swing.UIManager.setLookAndFeel(info.getClassName()); 207 | break; 208 | } 209 | } 210 | } catch (ClassNotFoundException ex) { 211 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 212 | } catch (InstantiationException ex) { 213 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 214 | } catch (IllegalAccessException ex) { 215 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 216 | } catch (javax.swing.UnsupportedLookAndFeelException ex) { 217 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 218 | } 219 | // 220 | 221 | /* 222 | * Create and display the form 223 | */ 224 | java.awt.EventQueue.invokeLater(new Runnable() { 225 | 226 | @Override 227 | public void run() { 228 | new GUI().setVisible(true); 229 | } 230 | }); 231 | } 232 | // Variables declaration - do not modify//GEN-BEGIN:variables 233 | private javax.swing.JTextField ip; 234 | private javax.swing.JLabel jLabel1; 235 | private javax.swing.JLabel jLabel2; 236 | private javax.swing.JLabel jLabel3; 237 | private javax.swing.JLabel jLabel4; 238 | private javax.swing.JProgressBar micLev; 239 | private javax.swing.JSlider micVol; 240 | private javax.swing.JTextField port; 241 | private javax.swing.JButton start; 242 | // End of variables declaration//GEN-END:variables 243 | } 244 | -------------------------------------------------------------------------------- /VoiceChat_Client/src/MicThread.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.ByteArrayOutputStream; 3 | import java.io.IOException; 4 | import java.io.ObjectOutputStream; 5 | import java.util.zip.GZIPOutputStream; 6 | import javax.sound.sampled.AudioFormat; 7 | import javax.sound.sampled.AudioSystem; 8 | import javax.sound.sampled.DataLine; 9 | import javax.sound.sampled.LineUnavailableException; 10 | import javax.sound.sampled.TargetDataLine; 11 | 12 | /* 13 | * To change this template, choose Tools | Templates 14 | * and open the template in the editor. 15 | */ 16 | /** 17 | * reads data from microphone and sends it to the server 18 | * 19 | * @author dosse 20 | */ 21 | public class MicThread extends Thread { 22 | 23 | public static double amplification = 1.0; 24 | private ObjectOutputStream toServer; 25 | private TargetDataLine mic; 26 | 27 | public MicThread(ObjectOutputStream toServer) throws LineUnavailableException { 28 | this.toServer = toServer; 29 | //open microphone line, an exception is thrown in case of error 30 | AudioFormat af = SoundPacket.defaultFormat; 31 | DataLine.Info info = new DataLine.Info(TargetDataLine.class, null); 32 | mic = (TargetDataLine) (AudioSystem.getLine(info)); 33 | mic.open(af); 34 | mic.start(); 35 | } 36 | 37 | @Override 38 | public void run() { 39 | for (;;) { 40 | if (mic.available() >= SoundPacket.defaultDataLenght) { //we got enough data to send 41 | byte[] buff = new byte[SoundPacket.defaultDataLenght]; 42 | while (mic.available() >= SoundPacket.defaultDataLenght) { //flush old data from mic to reduce lag, and read most recent data 43 | mic.read(buff, 0, buff.length); //read from microphone 44 | } 45 | try { 46 | //this part is used to decide whether to send or not the packet. if volume is too low, an empty packet will be sent and the remote client will play some comfort noise 47 | long tot = 0; 48 | for (int i = 0; i < buff.length; i++) { 49 | buff[i] *= amplification; 50 | tot += Math.abs(buff[i]); 51 | } 52 | tot *= 2.5; 53 | tot /= buff.length; 54 | //create and send packet 55 | Message m = null; 56 | if (tot == 0) {//send empty packet 57 | m = new Message(-1, -1, new SoundPacket(null)); 58 | } else { //send data 59 | //compress the sound packet with GZIP 60 | ByteArrayOutputStream baos = new ByteArrayOutputStream(); 61 | GZIPOutputStream go = new GZIPOutputStream(baos); 62 | go.write(buff); 63 | go.flush(); 64 | go.close(); 65 | baos.flush(); 66 | baos.close(); 67 | m = new Message(-1, -1, new SoundPacket(baos.toByteArray())); //create message for server, will generate chId and timestamp from this computer's IP and this socket's port 68 | } 69 | toServer.writeObject(m); //send message 70 | } catch (IOException ex) { //connection error 71 | stop(); 72 | } 73 | } else { 74 | Utils.sleep(10); //sleep to avoid busy wait 75 | } 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /VoiceChat_Comm/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /VoiceChat_Comm/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Builds, tests, and runs the project VoiceChat_Comm. 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /VoiceChat_Comm/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | X-COMMENT: Main-Class will be added automatically by build 3 | 4 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/build-impl.xml: -------------------------------------------------------------------------------- 1 | 2 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | Must set src.dir 224 | Must set test.src.dir 225 | Must set build.dir 226 | Must set dist.dir 227 | Must set build.classes.dir 228 | Must set dist.javadoc.dir 229 | Must set build.test.classes.dir 230 | Must set build.test.results.dir 231 | Must set build.classes.excludes 232 | Must set dist.jar 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 289 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 332 | 333 | Must set javac.includes 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 355 | 356 | 357 | 358 | 359 | 360 | 361 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 392 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 405 | 406 | 407 | 408 | 409 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 428 | 429 | 430 | 431 | 432 | 433 | 434 | 435 | 436 | 437 | 438 | 439 | 440 | 441 | 442 | 443 | 444 | 445 | 446 | 447 | 448 | 449 | 450 | 451 | 452 | 453 | 454 | 455 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | No tests executed. 463 | 464 | 465 | 466 | 467 | 468 | 469 | 470 | 471 | 472 | 473 | 474 | 475 | 476 | 477 | 478 | 479 | 480 | 481 | 482 | 483 | 484 | 485 | 486 | 487 | 488 | 489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 526 | 527 | 528 | 529 | 530 | 531 | 532 | 533 | 534 | 535 | 536 | 537 | 538 | 539 | 540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | 603 | 604 | 605 | 606 | 607 | 608 | 609 | 610 | 611 | 612 | 613 | 614 | 615 | 616 | 617 | 618 | 619 | 620 | 621 | 622 | 623 | 624 | 625 | 626 | 627 | 628 | 629 | 630 | 631 | 632 | 633 | 634 | 635 | 636 | 637 | 638 | 639 | 640 | 641 | 642 | 643 | 644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 655 | 656 | 657 | 658 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 670 | 671 | 672 | 673 | 674 | 675 | 676 | 677 | 678 | 679 | 680 | 681 | 682 | 683 | 684 | 685 | 686 | 687 | 688 | 689 | 690 | 691 | 692 | 693 | 694 | 695 | 696 | 697 | 698 | 699 | 700 | 701 | 702 | 703 | 704 | 705 | 706 | 707 | 708 | 709 | 710 | 711 | 712 | Must set JVM to use for profiling in profiler.info.jvm 713 | Must set profiler agent JVM arguments in profiler.info.jvmargs.agent 714 | 715 | 718 | 719 | 720 | 721 | 722 | 723 | 724 | 725 | 726 | 727 | 728 | 729 | 730 | 731 | 732 | 733 | 734 | 735 | 736 | 737 | 738 | 739 | 740 | 741 | 742 | 743 | 744 | 745 | 746 | 747 | 748 | 749 | 750 | 751 | 752 | 753 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 | 764 | 765 | 766 | 767 | 768 | 769 | 770 | 771 | 772 | 773 | 774 | 775 | 776 | 777 | 778 | 779 | 780 | 781 | 782 | 783 | 784 | 785 | 786 | 787 | 788 | 789 | 790 | 791 | 792 | 793 | 794 | 795 | 796 | 797 | 798 | 799 | 800 | 801 | 802 | 803 | 804 | 805 | 806 | 807 | 808 | 809 | 810 | 811 | 812 | 813 | 814 | 815 | 816 | 817 | 818 | 819 | 820 | 821 | 822 | 823 | 824 | 825 | 826 | 827 | 828 | 829 | 830 | 831 | 832 | 833 | 834 | 835 | 836 | 837 | 838 | 839 | 840 | 841 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 | 854 | 855 | 856 | 857 | 858 | 859 | 860 | 861 | 862 | 863 | 864 | 865 | 866 | 867 | 868 | 869 | 870 | 871 | 872 | 873 | 874 | 875 | 876 | 881 | 882 | 883 | 884 | 885 | 886 | 887 | 888 | 889 | 890 | 891 | 892 | 893 | 894 | 895 | 896 | 897 | 898 | 899 | 900 | 901 | 902 | 903 | 904 | 905 | 906 | 907 | 908 | 909 | 910 | 911 | 912 | 913 | 914 | 915 | 916 | 917 | 918 | 919 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 | 932 | 933 | 934 | 935 | 936 | 937 | 938 | 939 | 940 | 941 | Must select some files in the IDE or set javac.includes 942 | 943 | 944 | 945 | 946 | 947 | 948 | 949 | 950 | 955 | 956 | 957 | 958 | 959 | 960 | 961 | 962 | 963 | 964 | 965 | 966 | 967 | 968 | 969 | 970 | 971 | 972 | 973 | 974 | 975 | 976 | 977 | 978 | 979 | 980 | 981 | 982 | 983 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | To run this application from the command line without Ant, try: 992 | 993 | java -jar "${dist.jar.resolved}" 994 | 995 | 996 | 997 | 998 | 999 | 1000 | 1001 | 1002 | 1003 | 1004 | 1005 | 1006 | 1007 | 1008 | 1009 | 1010 | 1011 | 1012 | 1013 | 1014 | 1015 | 1016 | 1017 | 1018 | 1019 | 1020 | 1021 | 1022 | 1023 | 1024 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 | 1039 | 1040 | Must select one file in the IDE or set run.class 1041 | 1042 | 1043 | 1044 | Must select one file in the IDE or set run.class 1045 | 1046 | 1047 | 1052 | 1053 | 1054 | 1055 | 1056 | 1057 | 1058 | 1059 | 1060 | 1061 | 1062 | 1063 | 1064 | 1065 | 1066 | 1067 | 1068 | 1069 | 1070 | 1071 | Must select one file in the IDE or set debug.class 1072 | 1073 | 1074 | 1075 | 1076 | Must select one file in the IDE or set debug.class 1077 | 1078 | 1079 | 1080 | 1081 | Must set fix.includes 1082 | 1083 | 1084 | 1085 | 1086 | 1087 | 1088 | 1093 | 1096 | 1097 | This target only works when run from inside the NetBeans IDE. 1098 | 1099 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 | Must select one file in the IDE or set profile.class 1107 | This target only works when run from inside the NetBeans IDE. 1108 | 1109 | 1110 | 1111 | 1112 | 1113 | 1114 | 1115 | 1116 | This target only works when run from inside the NetBeans IDE. 1117 | 1118 | 1119 | 1120 | 1121 | 1122 | 1123 | 1124 | 1125 | 1126 | 1127 | 1128 | 1129 | This target only works when run from inside the NetBeans IDE. 1130 | 1131 | 1132 | 1133 | 1134 | 1135 | 1136 | 1137 | 1138 | 1139 | 1140 | 1141 | 1142 | 1143 | 1144 | 1145 | 1146 | 1147 | 1148 | 1149 | 1150 | 1151 | 1154 | 1155 | 1156 | 1157 | 1158 | 1159 | 1160 | 1161 | 1162 | 1163 | 1164 | 1165 | 1166 | 1167 | Must select one file in the IDE or set run.class 1168 | 1169 | 1170 | 1171 | 1172 | 1173 | Must select some files in the IDE or set test.includes 1174 | 1175 | 1176 | 1177 | 1178 | Must select one file in the IDE or set run.class 1179 | 1180 | 1181 | 1182 | 1183 | Must select one file in the IDE or set applet.url 1184 | 1185 | 1186 | 1187 | 1192 | 1193 | 1194 | 1195 | 1196 | 1197 | 1198 | 1199 | 1200 | 1201 | 1202 | 1203 | 1204 | 1205 | 1206 | 1207 | 1208 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1218 | 1219 | 1220 | 1221 | 1222 | 1223 | 1224 | 1225 | 1226 | 1227 | 1228 | 1233 | 1234 | 1235 | 1236 | 1237 | 1238 | 1239 | 1240 | 1241 | 1242 | 1243 | 1244 | 1245 | 1246 | 1247 | 1248 | 1249 | 1250 | 1251 | 1252 | 1253 | 1254 | 1255 | 1256 | 1257 | 1258 | 1259 | Must select some files in the IDE or set javac.includes 1260 | 1261 | 1262 | 1263 | 1264 | 1265 | 1266 | 1267 | 1268 | 1269 | 1270 | 1271 | 1276 | 1277 | 1278 | 1279 | 1280 | 1281 | 1282 | 1283 | Some tests failed; see details above. 1284 | 1285 | 1286 | 1287 | 1288 | 1289 | 1290 | 1291 | 1292 | Must select some files in the IDE or set test.includes 1293 | 1294 | 1295 | 1296 | Some tests failed; see details above. 1297 | 1298 | 1299 | 1300 | Must select some files in the IDE or set test.class 1301 | Must select some method in the IDE or set test.method 1302 | 1303 | 1304 | 1305 | Some tests failed; see details above. 1306 | 1307 | 1308 | 1313 | 1314 | Must select one file in the IDE or set test.class 1315 | 1316 | 1317 | 1318 | Must select one file in the IDE or set test.class 1319 | Must select some method in the IDE or set test.method 1320 | 1321 | 1322 | 1323 | 1324 | 1325 | 1326 | 1327 | 1328 | 1329 | 1330 | 1331 | 1336 | 1337 | Must select one file in the IDE or set applet.url 1338 | 1339 | 1340 | 1341 | 1342 | 1343 | 1344 | 1349 | 1350 | Must select one file in the IDE or set applet.url 1351 | 1352 | 1353 | 1354 | 1355 | 1356 | 1357 | 1358 | 1363 | 1364 | 1365 | 1366 | 1367 | 1368 | 1369 | 1370 | 1371 | 1372 | 1373 | 1374 | 1375 | 1376 | 1377 | 1378 | 1379 | 1380 | 1381 | 1382 | 1383 | 1384 | 1385 | 1386 | 1387 | 1388 | 1389 | 1390 | 1391 | 1392 | 1393 | 1394 | 1395 | 1396 | 1397 | 1398 | 1399 | 1400 | 1401 | 1402 | 1403 | 1404 | 1405 | 1406 | 1407 | 1408 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/genfiles.properties: -------------------------------------------------------------------------------- 1 | build.xml.data.CRC32=d9d52e4f 2 | build.xml.script.CRC32=57187d24 3 | build.xml.stylesheet.CRC32=8064a381@1.68.1.46 4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. 5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. 6 | nbproject/build-impl.xml.data.CRC32=d9d52e4f 7 | nbproject/build-impl.xml.script.CRC32=a271bca2 8 | nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46 9 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/private/config.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Comm/nbproject/private/config.properties -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/private/private.properties: -------------------------------------------------------------------------------- 1 | compile.on.save=true 2 | do.depend=false 3 | do.jar=true 4 | javac.debug=true 5 | javadoc.preview=true 6 | user.properties.file=C:\\Users\\dosse\\AppData\\Roaming\\NetBeans\\7.4\\build.properties 7 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/private/private.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/project.properties: -------------------------------------------------------------------------------- 1 | annotation.processing.enabled=true 2 | annotation.processing.enabled.in.editor=false 3 | annotation.processing.processors.list= 4 | annotation.processing.run.all.processors=true 5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output 6 | application.title=VoiceChat_Comm 7 | application.vendor=dosse 8 | build.classes.dir=${build.dir}/classes 9 | build.classes.excludes=**/*.java,**/*.form 10 | # This directory is removed when the project is cleaned: 11 | build.dir=build 12 | build.generated.dir=${build.dir}/generated 13 | build.generated.sources.dir=${build.dir}/generated-sources 14 | # Only compile against the classpath explicitly listed here: 15 | build.sysclasspath=ignore 16 | build.test.classes.dir=${build.dir}/test/classes 17 | build.test.results.dir=${build.dir}/test/results 18 | # Uncomment to specify the preferred debugger connection transport: 19 | #debug.transport=dt_socket 20 | debug.classpath=\ 21 | ${run.classpath} 22 | debug.test.classpath=\ 23 | ${run.test.classpath} 24 | # This directory is removed when the project is cleaned: 25 | dist.dir=dist 26 | dist.jar=${dist.dir}/VoiceChat_Comm.jar 27 | dist.javadoc.dir=${dist.dir}/javadoc 28 | endorsed.classpath= 29 | excludes= 30 | includes=** 31 | jar.archive.disabled=${jnlp.enabled} 32 | jar.compress=false 33 | jar.index=${jnlp.enabled} 34 | javac.classpath= 35 | # Space-separated list of extra javac options 36 | javac.compilerargs= 37 | javac.deprecation=false 38 | javac.processorpath=\ 39 | ${javac.classpath} 40 | javac.source=1.7 41 | javac.target=1.7 42 | javac.test.classpath=\ 43 | ${javac.classpath}:\ 44 | ${build.classes.dir} 45 | javac.test.processorpath=\ 46 | ${javac.test.classpath} 47 | javadoc.additionalparam= 48 | javadoc.author=false 49 | javadoc.encoding=${source.encoding} 50 | javadoc.noindex=false 51 | javadoc.nonavbar=false 52 | javadoc.notree=false 53 | javadoc.private=false 54 | javadoc.splitindex=true 55 | javadoc.use=true 56 | javadoc.version=false 57 | javadoc.windowtitle= 58 | jnlp.codebase.type=no.codebase 59 | jnlp.descriptor=application 60 | jnlp.enabled=false 61 | jnlp.mixed.code=default 62 | jnlp.offline-allowed=false 63 | jnlp.signed=false 64 | jnlp.signing= 65 | jnlp.signing.alias= 66 | jnlp.signing.keystore= 67 | main.class=ErrorMessage 68 | manifest.file=manifest.mf 69 | meta.inf.dir=${src.dir}/META-INF 70 | mkdist.disabled=false 71 | platform.active=default_platform 72 | run.classpath=\ 73 | ${javac.classpath}:\ 74 | ${build.classes.dir} 75 | # Space-separated list of JVM arguments used when running the project 76 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value 77 | # or test-sys-prop.name=value to set system properties for unit tests): 78 | run.jvmargs= 79 | run.test.classpath=\ 80 | ${javac.test.classpath}:\ 81 | ${build.test.classes.dir} 82 | source.encoding=UTF-8 83 | src.dir=src 84 | test.src.dir=test 85 | -------------------------------------------------------------------------------- /VoiceChat_Comm/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.java.j2seproject 4 | 5 | 6 | VoiceChat_Comm 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /VoiceChat_Comm/src/ErrorMessage.java: -------------------------------------------------------------------------------- 1 | 2 | import javax.swing.JOptionPane; 3 | 4 | /* 5 | * To change this template, choose Tools | Templates 6 | * and open the template in the editor. 7 | */ 8 | 9 | /** 10 | * 11 | * @author dosse 12 | */ 13 | public class ErrorMessage { 14 | public static void main(String args[]){ 15 | JOptionPane.showMessageDialog(new JOptionPane(),"This is a library, not a program.\nPlease run VoiceChat_Server or VoiceChat_Client"); 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /VoiceChat_Comm/src/Message.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.Serializable; 3 | 4 | /* 5 | * To change this template, choose Tools | Templates 6 | * and open the template in the editor. 7 | */ 8 | 9 | /** 10 | * container for any type of object to be sent 11 | * @author dosse 12 | */ 13 | public class Message implements Serializable{ 14 | private long chId; //-1 means from client to server, otherwise chId generated by the server 15 | private long timestamp, //-1 means from client to server, otherwise timeStamp of the moment when the server receives the message 16 | ttl=2000; //2 seconds TTL 17 | private Object data; //can carry any type of object. in this program, i used a sound packet, but it could be a string, a chunk of video, ... 18 | 19 | 20 | public Message(long chId, long timestamp, Object data) { 21 | this.chId = chId; 22 | this.timestamp = timestamp; 23 | this.data = data; 24 | } 25 | 26 | public void setTimestamp(long timestamp) { 27 | this.timestamp = timestamp; 28 | } 29 | 30 | public long getChId() { 31 | return chId; 32 | } 33 | 34 | public Object getData() { 35 | return data; 36 | } 37 | 38 | public long getTimestamp() { 39 | return timestamp; 40 | } 41 | 42 | public long getTtl() { 43 | return ttl; 44 | } 45 | public void setTtl(long ttl) { 46 | this.ttl = ttl; 47 | } 48 | 49 | public void setChId(long chId) { 50 | this.chId = chId; 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /VoiceChat_Comm/src/SoundPacket.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.Serializable; 3 | import javax.sound.sampled.AudioFormat; 4 | 5 | /* 6 | * To change this template, choose Tools | Templates 7 | * and open the template in the editor. 8 | */ 9 | 10 | /** 11 | * some sound 12 | * @author dosse 13 | */ 14 | public class SoundPacket implements Serializable{ 15 | public static AudioFormat defaultFormat=new AudioFormat(11025f, 8, 1, true, true); //11.025khz, 8bit, mono, signed, big endian (changes nothing in 8 bit) ~8kb/s 16 | public static int defaultDataLenght=1200; //send 1200 samples/packet by default 17 | private byte[] data; //actual data. if null, comfort noise will be played 18 | 19 | public SoundPacket(byte[] data) { 20 | this.data = data; 21 | } 22 | 23 | public byte[] getData() { 24 | return data; 25 | } 26 | 27 | } 28 | -------------------------------------------------------------------------------- /VoiceChat_Comm/src/Utils.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.BufferedReader; 3 | import java.io.InputStreamReader; 4 | import java.net.InetAddress; 5 | import java.net.URL; 6 | import java.net.UnknownHostException; 7 | 8 | 9 | 10 | /* 11 | * To change this template, choose Tools | Templates 12 | * and open the template in the editor. 13 | */ 14 | 15 | /** 16 | * contains some static methods used here and there in the code 17 | * @author dosse 18 | */ 19 | public class Utils { 20 | public static void sleep(int ms){ 21 | try {Thread.sleep(ms);} catch (InterruptedException ex) {} 22 | } 23 | public static String getExternalIP(){ 24 | try { 25 | URL myIp=new URL("http://checkip.dyndns.org/"); 26 | BufferedReader in=new BufferedReader(new InputStreamReader(myIp.openStream())); 27 | String s=in.readLine(); 28 | return s.substring(s.lastIndexOf(":")+2,s.lastIndexOf("")); 29 | } catch (Exception ex) { 30 | return "error "+ex; 31 | } 32 | } 33 | public static String getInternalIP(){ 34 | try { 35 | return InetAddress.getLocalHost().getHostAddress(); 36 | } catch (UnknownHostException ex) { 37 | return "error"; 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /VoiceChat_Server/.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | dist/ 3 | -------------------------------------------------------------------------------- /VoiceChat_Server/build.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | Builds, tests, and runs the project VoiceChat_Server. 12 | 13 | 73 | 74 | -------------------------------------------------------------------------------- /VoiceChat_Server/lib/cling-core-1.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Server/lib/cling-core-1.0.5.jar -------------------------------------------------------------------------------- /VoiceChat_Server/lib/cling-support-1.0.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Server/lib/cling-support-1.0.5.jar -------------------------------------------------------------------------------- /VoiceChat_Server/lib/teleal-common-1.0.13.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Server/lib/teleal-common-1.0.13.jar -------------------------------------------------------------------------------- /VoiceChat_Server/manifest.mf: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | X-COMMENT: Main-Class will be added automatically by build 3 | 4 | -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/genfiles.properties: -------------------------------------------------------------------------------- 1 | build.xml.data.CRC32=9b294d54 2 | build.xml.script.CRC32=94163f0b 3 | build.xml.stylesheet.CRC32=8064a381@1.68.1.46 4 | # This file is used by a NetBeans-based IDE to track changes in generated files such as build-impl.xml. 5 | # Do not edit this file. You may delete it but then the IDE will never regenerate such files for you. 6 | nbproject/build-impl.xml.data.CRC32=9b294d54 7 | nbproject/build-impl.xml.script.CRC32=0443cf3d 8 | nbproject/build-impl.xml.stylesheet.CRC32=5a01deb7@1.68.1.46 9 | -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/private/config.properties: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/adolfintel/voicechat/10878e2beb334ff863f66914f3b2852c72c0d410/VoiceChat_Server/nbproject/private/config.properties -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/private/private.properties: -------------------------------------------------------------------------------- 1 | compile.on.save=true 2 | do.depend=false 3 | do.jar=true 4 | javac.debug=true 5 | javadoc.preview=true 6 | user.properties.file=C:\\Users\\dosse\\AppData\\Roaming\\NetBeans\\7.4\\build.properties 7 | -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/private/private.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | file:/C:/Users/dosse/Documents/NetBeansProjects/VoiceChat_Server/src/GUI.java 8 | file:/C:/Users/dosse/Documents/NetBeansProjects/VoiceChat_Server/src/Server.java 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/project.properties: -------------------------------------------------------------------------------- 1 | annotation.processing.enabled=true 2 | annotation.processing.enabled.in.editor=false 3 | annotation.processing.processors.list= 4 | annotation.processing.run.all.processors=true 5 | annotation.processing.source.output=${build.generated.sources.dir}/ap-source-output 6 | application.title=VoiceChat_Server 7 | application.vendor=dosse 8 | build.classes.dir=${build.dir}/classes 9 | build.classes.excludes=**/*.java,**/*.form 10 | # This directory is removed when the project is cleaned: 11 | build.dir=build 12 | build.generated.dir=${build.dir}/generated 13 | build.generated.sources.dir=${build.dir}/generated-sources 14 | # Only compile against the classpath explicitly listed here: 15 | build.sysclasspath=ignore 16 | build.test.classes.dir=${build.dir}/test/classes 17 | build.test.results.dir=${build.dir}/test/results 18 | # Uncomment to specify the preferred debugger connection transport: 19 | #debug.transport=dt_socket 20 | debug.classpath=\ 21 | ${run.classpath} 22 | debug.test.classpath=\ 23 | ${run.test.classpath} 24 | # This directory is removed when the project is cleaned: 25 | dist.dir=dist 26 | dist.jar=${dist.dir}/VoiceChat_Server.jar 27 | dist.javadoc.dir=${dist.dir}/javadoc 28 | endorsed.classpath= 29 | excludes= 30 | file.reference.cling-core-1.0.5.jar=lib/cling-core-1.0.5.jar 31 | file.reference.cling-support-1.0.5.jar=lib/cling-support-1.0.5.jar 32 | file.reference.teleal-common-1.0.13.jar=lib/teleal-common-1.0.13.jar 33 | includes=** 34 | jar.archive.disabled=${jnlp.enabled} 35 | jar.compress=false 36 | jar.index=${jnlp.enabled} 37 | javac.classpath=\ 38 | ${file.reference.cling-core-1.0.5.jar}:\ 39 | ${file.reference.cling-support-1.0.5.jar}:\ 40 | ${file.reference.teleal-common-1.0.13.jar}:\ 41 | ${reference.VoiceChat_Comm.jar} 42 | # Space-separated list of extra javac options 43 | javac.compilerargs= 44 | javac.deprecation=false 45 | javac.processorpath=\ 46 | ${javac.classpath} 47 | javac.source=1.7 48 | javac.target=1.7 49 | javac.test.classpath=\ 50 | ${javac.classpath}:\ 51 | ${build.classes.dir} 52 | javac.test.processorpath=\ 53 | ${javac.test.classpath} 54 | javadoc.additionalparam= 55 | javadoc.author=false 56 | javadoc.encoding=${source.encoding} 57 | javadoc.noindex=false 58 | javadoc.nonavbar=false 59 | javadoc.notree=false 60 | javadoc.private=false 61 | javadoc.splitindex=true 62 | javadoc.use=true 63 | javadoc.version=false 64 | javadoc.windowtitle= 65 | jnlp.codebase.type=no.codebase 66 | jnlp.descriptor=application 67 | jnlp.enabled=false 68 | jnlp.mixed.code=default 69 | jnlp.offline-allowed=false 70 | jnlp.signed=false 71 | jnlp.signing= 72 | jnlp.signing.alias= 73 | jnlp.signing.keystore= 74 | main.class=GUI 75 | manifest.file=manifest.mf 76 | meta.inf.dir=${src.dir}/META-INF 77 | mkdist.disabled=false 78 | platform.active=default_platform 79 | project.VoiceChat_Comm=../VoiceChat_Comm 80 | reference.VoiceChat_Comm.jar=${project.VoiceChat_Comm}/dist/VoiceChat_Comm.jar 81 | run.classpath=\ 82 | ${javac.classpath}:\ 83 | ${build.classes.dir} 84 | # Space-separated list of JVM arguments used when running the project 85 | # (you may also define separate properties like run-sys-prop.name=value instead of -Dname=value 86 | # or test-sys-prop.name=value to set system properties for unit tests): 87 | run.jvmargs= 88 | run.test.classpath=\ 89 | ${javac.test.classpath}:\ 90 | ${build.test.classes.dir} 91 | source.encoding=UTF-8 92 | src.dir=src 93 | test.src.dir=test 94 | -------------------------------------------------------------------------------- /VoiceChat_Server/nbproject/project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | org.netbeans.modules.java.j2seproject 4 | 5 | 6 | VoiceChat_Server 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | VoiceChat_Comm 17 | jar 18 | 19 | jar 20 | clean 21 | jar 22 | 23 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /VoiceChat_Server/src/ClientConnection.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.IOException; 3 | import java.io.ObjectInputStream; 4 | import java.io.ObjectOutputStream; 5 | import java.net.InetAddress; 6 | import java.net.Socket; 7 | import java.util.ArrayList; 8 | 9 | /* 10 | * To change this template, choose Tools | Templates and open the template in 11 | * the editor. 12 | */ 13 | /** 14 | * this thread manages a connection with a client. it does a lot of stuff: -read 15 | * messages from client -add said messages to the server's broadcast queue 16 | * -receive messages from the server thread -add said messages to a send queue 17 | * -send messages from said queue to the client (or throw them away if too old) 18 | * 19 | * @author dosse 20 | */ 21 | public class ClientConnection extends Thread { 22 | 23 | private Server serv; //instance of server, needed to put messages in the server's broadcast queue 24 | private Socket s; //connection to client 25 | private ObjectInputStream in; //object streams to/from client 26 | private ObjectOutputStream out; 27 | private long chId; //unique id of this client, generated in the costructor 28 | private ArrayList toSend = new ArrayList(); //queue of messages to be sent to the client 29 | 30 | public InetAddress getInetAddress() { //returns this client's ip address 31 | return s.getInetAddress(); 32 | } 33 | 34 | public int getPort() { //returns this client's tcp port 35 | return s.getPort(); 36 | } 37 | 38 | public long getChId() { //return this client's unique id 39 | return chId; 40 | } 41 | 42 | public ClientConnection(Server serv, Socket s) { 43 | this.serv = serv; 44 | this.s = s; 45 | byte[] addr = s.getInetAddress().getAddress(); 46 | chId = (addr[0] << 48 | addr[1] << 32 | addr[2] << 24 | addr[3] << 16) + s.getPort(); //generate unique chId from client's IP and port 47 | } 48 | 49 | public void addToQueue(Message m) { //add a message to send to the client 50 | try { 51 | toSend.add(m); 52 | } catch (Throwable t) { 53 | //mutex error, ignore because the server must be as fast as possible 54 | } 55 | } 56 | 57 | @Override 58 | public void run() { 59 | try { 60 | out = new ObjectOutputStream(s.getOutputStream()); //create object streams to/from client 61 | in = new ObjectInputStream(s.getInputStream()); 62 | } catch (IOException ex) { //connection error, close connection 63 | try { 64 | s.close(); 65 | Log.add("ERROR " + getInetAddress() + ":" + getPort() + " " + ex); 66 | } catch (IOException ex1) { 67 | } 68 | stop(); 69 | } 70 | for (;;) { 71 | try { 72 | if (s.getInputStream().available() > 0) { //we got something from the client 73 | Message toBroadcast = (Message) in.readObject(); //read data from client 74 | if (toBroadcast.getChId() == -1) { //set its chId and timestamp and pass it to the server 75 | toBroadcast.setChId(chId); 76 | toBroadcast.setTimestamp(System.nanoTime() / 1000000L); 77 | serv.addToBroadcastQueue(toBroadcast); 78 | } else { 79 | continue; //invalid message 80 | } 81 | } 82 | try { 83 | if (!toSend.isEmpty()) { 84 | Message toClient = toSend.get(0); //we got something to send to the client 85 | if (!(toClient.getData() instanceof SoundPacket) || toClient.getTimestamp() + toClient.getTtl() < System.nanoTime() / 1000000L) { //is the message too old or of an unknown type? 86 | Log.add("dropping packet from " + toClient.getChId() + " to " + chId); 87 | continue; 88 | } 89 | out.writeObject(toClient); //send the message 90 | toSend.remove(toClient); //and remove it from the queue 91 | } else { 92 | Utils.sleep(10); //avoid busy wait 93 | } 94 | } catch (Throwable t) { 95 | if (t instanceof IOException) {//connection closed or connection error 96 | throw (Exception) t; 97 | } else {//mutex error, try again 98 | System.out.println("cc fixmutex"); 99 | continue; 100 | } 101 | } 102 | } catch (Exception ex) { //connection closed or connection error, kill thread 103 | try { 104 | s.close(); 105 | } catch (IOException ex1) { 106 | } 107 | stop(); 108 | } 109 | } 110 | 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /VoiceChat_Server/src/GUI.form: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 |
108 | -------------------------------------------------------------------------------- /VoiceChat_Server/src/GUI.java: -------------------------------------------------------------------------------- 1 | 2 | import java.util.logging.Level; 3 | import java.util.logging.Logger; 4 | import javax.swing.JOptionPane; 5 | 6 | 7 | 8 | /* 9 | * To change this template, choose Tools | Templates and open the template in 10 | * the editor. 11 | */ 12 | /** 13 | * 14 | * @author dosse 15 | */ 16 | public class GUI extends javax.swing.JFrame { 17 | 18 | /** 19 | * Creates new form GUI 20 | */ 21 | public GUI() { 22 | initComponents(); 23 | } 24 | 25 | /** 26 | * This method is called from within the constructor to initialize the form. 27 | * WARNING: Do NOT modify this code. The content of this method is always 28 | * regenerated by the Form Editor. 29 | */ 30 | @SuppressWarnings("unchecked") 31 | // //GEN-BEGIN:initComponents 32 | private void initComponents() { 33 | 34 | jLabel1 = new javax.swing.JLabel(); 35 | jTextField1 = new javax.swing.JTextField(); 36 | jButton1 = new javax.swing.JButton(); 37 | jScrollPane1 = new javax.swing.JScrollPane(); 38 | log = new javax.swing.JTextArea(); 39 | upnp = new javax.swing.JCheckBox(); 40 | 41 | setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); 42 | 43 | jLabel1.setText("Listen on port"); 44 | 45 | jTextField1.setText("1049"); 46 | 47 | jButton1.setText("Start"); 48 | jButton1.addActionListener(new java.awt.event.ActionListener() { 49 | public void actionPerformed(java.awt.event.ActionEvent evt) { 50 | jButton1ActionPerformed(evt); 51 | } 52 | }); 53 | 54 | log.setEditable(false); 55 | log.setColumns(20); 56 | log.setRows(5); 57 | log.setBorder(null); 58 | jScrollPane1.setViewportView(log); 59 | 60 | upnp.setSelected(true); 61 | upnp.setText("uPnP NAT Port Forwarding"); 62 | 63 | javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); 64 | getContentPane().setLayout(layout); 65 | layout.setHorizontalGroup( 66 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 67 | .addGroup(layout.createSequentialGroup() 68 | .addContainerGap() 69 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 70 | .addComponent(jScrollPane1) 71 | .addGroup(layout.createSequentialGroup() 72 | .addComponent(jLabel1) 73 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 74 | .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, 50, javax.swing.GroupLayout.PREFERRED_SIZE) 75 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 76 | .addComponent(jButton1) 77 | .addGap(0, 154, Short.MAX_VALUE)) 78 | .addComponent(upnp, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) 79 | .addContainerGap()) 80 | ); 81 | layout.setVerticalGroup( 82 | layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) 83 | .addGroup(layout.createSequentialGroup() 84 | .addContainerGap() 85 | .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) 86 | .addComponent(jLabel1) 87 | .addComponent(jTextField1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) 88 | .addComponent(jButton1)) 89 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 90 | .addComponent(upnp) 91 | .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) 92 | .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 159, Short.MAX_VALUE) 93 | .addContainerGap()) 94 | ); 95 | 96 | pack(); 97 | }// //GEN-END:initComponents 98 | 99 | private void jButton1ActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_jButton1ActionPerformed 100 | if (jButton1.getText().equals("Stop")) { 101 | System.exit(0); 102 | } 103 | new Thread() { //start server in new thread 104 | 105 | @Override 106 | public void run() { 107 | try { 108 | new Server(Integer.parseInt(jTextField1.getText()),upnp.isSelected()); 109 | } catch (Exception ex) { 110 | JOptionPane.showMessageDialog(rootPane,ex,getTitle(),JOptionPane.ERROR_MESSAGE); 111 | System.exit(0); 112 | } 113 | } 114 | }.start(); 115 | new Thread() { //start logger 116 | @Override 117 | public void run() { 118 | for (;;) { 119 | Utils.sleep(100); 120 | if (!Log.get().equals(log.getText())) { 121 | log.setText(Log.get()); 122 | log.getCaret().setDot(Log.get().length()); 123 | } 124 | } 125 | } 126 | }.start(); 127 | jTextField1.setEnabled(false); 128 | jButton1.setText("Stop"); 129 | }//GEN-LAST:event_jButton1ActionPerformed 130 | 131 | /** 132 | * @param args the command line arguments 133 | */ 134 | public static void main(String args[]) { 135 | /* 136 | * Set the Nimbus look and feel 137 | */ 138 | // 139 | /* 140 | * If Nimbus (introduced in Java SE 6) is not available, stay with the 141 | * default look and feel. For details see 142 | * http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 143 | */ 144 | try { 145 | for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels()) { 146 | if ("Nimbus".equals(info.getName())) { 147 | javax.swing.UIManager.setLookAndFeel(info.getClassName()); 148 | break; 149 | } 150 | } 151 | } catch (ClassNotFoundException ex) { 152 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 153 | } catch (InstantiationException ex) { 154 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 155 | } catch (IllegalAccessException ex) { 156 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 157 | } catch (javax.swing.UnsupportedLookAndFeelException ex) { 158 | java.util.logging.Logger.getLogger(GUI.class.getName()).log(java.util.logging.Level.SEVERE, null, ex); 159 | } 160 | // 161 | 162 | /* 163 | * Create and display the form 164 | */ 165 | java.awt.EventQueue.invokeLater(new Runnable() { 166 | 167 | @Override 168 | public void run() { 169 | new GUI().setVisible(true); 170 | } 171 | }); 172 | } 173 | // Variables declaration - do not modify//GEN-BEGIN:variables 174 | private javax.swing.JButton jButton1; 175 | private javax.swing.JLabel jLabel1; 176 | private javax.swing.JScrollPane jScrollPane1; 177 | private javax.swing.JTextField jTextField1; 178 | private javax.swing.JTextArea log; 179 | private javax.swing.JCheckBox upnp; 180 | // End of variables declaration//GEN-END:variables 181 | } 182 | -------------------------------------------------------------------------------- /VoiceChat_Server/src/Log.java: -------------------------------------------------------------------------------- 1 | /* 2 | * To change this template, choose Tools | Templates 3 | * and open the template in the editor. 4 | */ 5 | 6 | /** 7 | * server's log. instances of Server add entries to this log 8 | * @author dosse 9 | */ 10 | public class Log { 11 | private static String log=""; 12 | public static void add(String s){log+=s+"\n";} 13 | public static String get(){return log;} 14 | } 15 | -------------------------------------------------------------------------------- /VoiceChat_Server/src/Server.java: -------------------------------------------------------------------------------- 1 | 2 | import java.io.IOException; 3 | import java.net.Inet4Address; 4 | import java.net.InetAddress; 5 | import java.net.NetworkInterface; 6 | import java.net.ServerSocket; 7 | import java.net.Socket; 8 | import java.net.SocketException; 9 | import java.util.ArrayList; 10 | import java.util.Enumeration; 11 | import org.teleal.cling.UpnpService; 12 | import org.teleal.cling.UpnpServiceImpl; 13 | import org.teleal.cling.support.igd.PortMappingListener; 14 | import org.teleal.cling.support.model.PortMapping; 15 | 16 | /* 17 | * To change this template, choose Tools | Templates and open the template in 18 | * the editor. 19 | */ 20 | /** 21 | * opens a socket, listens for incoming connections, and creates a 22 | * ClientConnection for each client. also creates a BroadcastThread that passes 23 | * messages from the broadcastQueue to all the instances of ClientConnection 24 | * 25 | * @author dosse 26 | */ 27 | public class Server { 28 | 29 | private ArrayList broadCastQueue = new ArrayList(); 30 | private ArrayList clients = new ArrayList(); 31 | private int port; 32 | 33 | private UpnpService u; //when upnp is enabled, this points to the upnp service 34 | 35 | public void addToBroadcastQueue(Message m) { //add a message to the broadcast queue. this method is used by all ClientConnection instances 36 | try { 37 | broadCastQueue.add(m); 38 | } catch (Throwable t) { 39 | //mutex error, try again 40 | Utils.sleep(1); 41 | addToBroadcastQueue(m); 42 | } 43 | } 44 | private ServerSocket s; 45 | 46 | public Server(int port, boolean upnp) throws Exception{ 47 | this.port = port; 48 | if(upnp){ 49 | Log.add("Setting up NAT Port Forwarding..."); 50 | //first we need the address of this machine on the local network 51 | try { 52 | Enumeration interfaces = NetworkInterface.getNetworkInterfaces(); 53 | } catch (SocketException ex) { 54 | Log.add("Network error"); 55 | throw new Exception("Network error"); 56 | } 57 | String ipAddress = null; 58 | Enumeration net = null; 59 | try { 60 | net = NetworkInterface.getNetworkInterfaces(); 61 | } catch (SocketException e) { 62 | Log.add("Not connected to any network"); 63 | throw new Exception("Network error"); 64 | } 65 | 66 | while (net.hasMoreElements()) { 67 | NetworkInterface element = net.nextElement(); 68 | Enumeration addresses = element.getInetAddresses(); 69 | while (addresses.hasMoreElements()) { 70 | InetAddress ip = addresses.nextElement(); 71 | if (ip instanceof Inet4Address) { 72 | if (ip.isSiteLocalAddress()) { 73 | ipAddress = ip.getHostAddress(); 74 | break; 75 | } 76 | } 77 | } 78 | if (ipAddress != null) { 79 | break; 80 | } 81 | } 82 | if (ipAddress == null) { 83 | Log.add("Not connected to any IPv4 network"); 84 | throw new Exception("Network error"); 85 | } 86 | u = new UpnpServiceImpl(new PortMappingListener(new PortMapping(port, ipAddress, PortMapping.Protocol.TCP))); 87 | u.getControlPoint().search(); 88 | } 89 | try { 90 | s = new ServerSocket(port); //listen on specified port 91 | Log.add("Port " + port + ": server started"); 92 | } catch (IOException ex) { 93 | Log.add("Server error " + ex + "(port " + port + ")"); 94 | throw new Exception("Error "+ex); 95 | } 96 | new BroadcastThread().start(); //create a BroadcastThread and start it 97 | for (;;) { //accept all incoming connection 98 | try { 99 | Socket c = s.accept(); 100 | ClientConnection cc = new ClientConnection(this, c); //create a ClientConnection thread 101 | cc.start(); 102 | addToClients(cc); 103 | Log.add("new client " + c.getInetAddress() + ":" + c.getPort() + " on port " + port); 104 | } catch (IOException ex) { 105 | } 106 | } 107 | } 108 | 109 | private void addToClients(ClientConnection cc) { 110 | try { 111 | clients.add(cc); //add the new connection to the list of connections 112 | } catch (Throwable t) { 113 | //mutex error, try again 114 | Utils.sleep(1); 115 | addToClients(cc); 116 | } 117 | } 118 | 119 | /** 120 | * broadcasts messages to each ClientConnection, and removes dead ones 121 | */ 122 | private class BroadcastThread extends Thread { 123 | 124 | public BroadcastThread() { 125 | } 126 | 127 | @Override 128 | public void run() { 129 | for (;;) { 130 | try { 131 | ArrayList toRemove = new ArrayList(); //create a list of dead connections 132 | for (ClientConnection cc : clients) { 133 | if (!cc.isAlive()) { //connection is dead, need to be removed 134 | Log.add("dead connection closed: " + cc.getInetAddress() + ":" + cc.getPort() + " on port " + port); 135 | toRemove.add(cc); 136 | } 137 | } 138 | clients.removeAll(toRemove); //delete all dead connections 139 | if (broadCastQueue.isEmpty()) { //nothing to send 140 | Utils.sleep(10); //avoid busy wait 141 | continue; 142 | } else { //we got something to broadcast 143 | Message m = broadCastQueue.get(0); 144 | for (ClientConnection cc : clients) { //broadcast the message 145 | if (cc.getChId() != m.getChId()) { 146 | cc.addToQueue(m); 147 | } 148 | } 149 | broadCastQueue.remove(m); //remove it from the broadcast queue 150 | } 151 | } catch (Throwable t) { 152 | //mutex error, try again 153 | } 154 | } 155 | } 156 | } 157 | } 158 | --------------------------------------------------------------------------------