// Path: TCC/src/Dependencias/Message.java
// public class Message implements Serializable {
// 
//     private long chId; //-1 means from client to server, otherwise chId generated by the server
//     private long timestamp, //-1 means from client to server, otherwise timeStamp of the moment when the server receives the message
//             ttl = 2000; //2 seconds TTL
//     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, ...
// 
//     public Message(long chId, long timestamp, Object data) {
//         this.chId = chId;
//         this.timestamp = timestamp;
//         this.data = data;
//     }
// 
//     public void setTimestamp(long timestamp) {
//         this.timestamp = timestamp;
//     }
// 
//     public long getChId() {
//         return chId;
//     }
// 
//     public Object getData() {
//         return data;
//     }
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public long getTtl() {
//         return ttl;
//     }
// 
//     public void setTtl(long ttl) {
//         this.ttl = ttl;
//     }
// 
//     public void setChId(long chId) {
//         this.chId = chId;
//     }
// 
// }
// 
// Path: TCC/src/Dependencias/SoundPacket.java
// public class SoundPacket implements Serializable {
// 
//     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
//     public static int defaultDataLenght = 1200; //send 1200 samples/packet by default
//     private byte[] data; //actual data. if null, comfort noise will be played
// 
//     public SoundPacket(byte[] data) {
//         this.data = data;
//     }
// 
//     public byte[] getData() {
//         return data;
//     }
// 
// }
// 
// Path: TCC/src/Dependencias/Utils.java
// public class Utils {
// 
//     public static void sleep(int ms) {
//         try {
//             Thread.sleep(ms);
//         } catch (InterruptedException ex) {
//         }
//     }
// 
//     public static String getExternalIP() {
//         try {
//             URL myIp = new URL("http://checkip.dyndns.org/");
//             BufferedReader in = new BufferedReader(new InputStreamReader(myIp.openStream()));
//             String s = in.readLine();
//             return s.substring(s.lastIndexOf(":") + 2, s.lastIndexOf("</body>"));
//         } catch (Exception ex) {
//             return "error " + ex;
//         }
//     }
// 
//     public static String getInternalIP() {
//         try {
//             return InetAddress.getLocalHost().getHostAddress();
//         } catch (UnknownHostException ex) {
//             return "error";
//         }
//     }
// }


import Dependencias.Message;
import Dependencias.SoundPacket;
import Dependencias.Utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPOutputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
package ClienteVoIP;


public class MicThread extends Thread {

    public static double amplification = 1.0;
    private ObjectOutputStream toServer;
    private TargetDataLine mic;

    public MicThread(ObjectOutputStream toServer) throws LineUnavailableException {
        this.toServer = toServer;
        //open microphone line, an exception is thrown in case of error
        AudioFormat af = SoundPacket.defaultFormat;
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, null);
        mic = (TargetDataLine) (AudioSystem.getLine(info));
        mic.open(af);
        mic.start();
    }

    @Override
    public void run() {
        for (;;) {
            if (mic.available() >= SoundPacket.defaultDataLenght) { //we got enough data to send
                byte[] buff = new byte[SoundPacket.defaultDataLenght];
                while (mic.available() >= SoundPacket.defaultDataLenght) { //flush old data from mic to reduce lag, and read most recent data
                    mic.read(buff, 0, buff.length); //read from microphone
                }
                try {
                    //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
                    long tot = 0;
                    for (int i = 0; i < buff.length; i++) {
                        buff[i] *= amplification;
                        tot += Math.abs(buff[i]);
                    }
                    tot *= 2.5;
                    tot /= buff.length;
                    //create and send packet
// Path: TCC/src/Dependencias/Message.java
// public class Message implements Serializable {
// 
//     private long chId; //-1 means from client to server, otherwise chId generated by the server
//     private long timestamp, //-1 means from client to server, otherwise timeStamp of the moment when the server receives the message
//             ttl = 2000; //2 seconds TTL
//     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, ...
// 
//     public Message(long chId, long timestamp, Object data) {
//         this.chId = chId;
//         this.timestamp = timestamp;
//         this.data = data;
//     }
// 
//     public void setTimestamp(long timestamp) {
//         this.timestamp = timestamp;
//     }
// 
//     public long getChId() {
//         return chId;
//     }
// 
//     public Object getData() {
//         return data;
//     }
// 
//     public long getTimestamp() {
//         return timestamp;
//     }
// 
//     public long getTtl() {
//         return ttl;
//     }
// 
//     public void setTtl(long ttl) {
//         this.ttl = ttl;
//     }
// 
//     public void setChId(long chId) {
//         this.chId = chId;
//     }
// 
// }
// 
// Path: TCC/src/Dependencias/SoundPacket.java
// public class SoundPacket implements Serializable {
// 
//     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
//     public static int defaultDataLenght = 1200; //send 1200 samples/packet by default
//     private byte[] data; //actual data. if null, comfort noise will be played
// 
//     public SoundPacket(byte[] data) {
//         this.data = data;
//     }
// 
//     public byte[] getData() {
//         return data;
//     }
// 
// }
// 
// Path: TCC/src/Dependencias/Utils.java
// public class Utils {
// 
//     public static void sleep(int ms) {
//         try {
//             Thread.sleep(ms);
//         } catch (InterruptedException ex) {
//         }
//     }
// 
//     public static String getExternalIP() {
//         try {
//             URL myIp = new URL("http://checkip.dyndns.org/");
//             BufferedReader in = new BufferedReader(new InputStreamReader(myIp.openStream()));
//             String s = in.readLine();
//             return s.substring(s.lastIndexOf(":") + 2, s.lastIndexOf("</body>"));
//         } catch (Exception ex) {
//             return "error " + ex;
//         }
//     }
// 
//     public static String getInternalIP() {
//         try {
//             return InetAddress.getLocalHost().getHostAddress();
//         } catch (UnknownHostException ex) {
//             return "error";
//         }
//     }
// }


// Path: TCC/src/ClienteVoIP/MicThread.java
import Dependencias.Message;
import Dependencias.SoundPacket;
import Dependencias.Utils;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.util.zip.GZIPOutputStream;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;

package ClienteVoIP;


public class MicThread extends Thread {

    public static double amplification = 1.0;
    private ObjectOutputStream toServer;
    private TargetDataLine mic;

    public MicThread(ObjectOutputStream toServer) throws LineUnavailableException {
        this.toServer = toServer;
        //open microphone line, an exception is thrown in case of error
        AudioFormat af = SoundPacket.defaultFormat;
        DataLine.Info info = new DataLine.Info(TargetDataLine.class, null);
        mic = (TargetDataLine) (AudioSystem.getLine(info));
        mic.open(af);
        mic.start();
    }

    @Override
    public void run() {
        for (;;) {
            if (mic.available() >= SoundPacket.defaultDataLenght) { //we got enough data to send
                byte[] buff = new byte[SoundPacket.defaultDataLenght];
                while (mic.available() >= SoundPacket.defaultDataLenght) { //flush old data from mic to reduce lag, and read most recent data
                    mic.read(buff, 0, buff.length); //read from microphone
                }
                try {
                    //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
                    long tot = 0;
                    for (int i = 0; i < buff.length; i++) {
                        buff[i] *= amplification;
                        tot += Math.abs(buff[i]);
                    }
                    tot *= 2.5;
                    tot /= buff.length;
                    //create and send packet
                    Message m = null;