JavaRanch » Java Forums »
Java »
Sockets and Internet Protocols
| Author |
Voice Chat Open Source
|
omer omran
Greenhorn
Joined: Mar 24, 2004
Posts: 3
|
|
Here is the source code of the idea of the voice chat I need some modification to be multi voice chat on the internet ************************************************************************ // read this first ************************************************************************ These programs were written in Java 1.4.1 on Windows XP. There are two, Sender.java and Receiver.java Sender.java takes audio input and sends it onto the network. Receiver.java gets audio input off of the network and plays it. The sound part of the program does not specify explicitly what mixers should be used, so it should not be a problem running on other computers. The network hostname "localhost" is used by the Sending Program. This is set on line 159 of Sender.java, if you'd need to change it. The port used is 6001. To compile, type: javac *.java To run, start two terminals and run one in each with no arguments. ie: java Sender.java java Receiver.java ************************************************************************ Receiver.java ************************************************************************ import javax.sound.sampled.*; import java.io.*; import java.net.*; import java.util.*; public class Receiver extends Thread{ private static final intDEFAULT_INTERNAL_BUFSIZ = 20480; //Audio Buffer Sizes private static final intDEFAULT_EXTERNAL_BUFSIZ = 20480; private SourceDataLinem_sourceLine; //Line for Audio Out private booleanm_bRecording; private intm_nExternalBufferSize; static boolean goflag; static int PacketsIN; int stepSizeTable[] = { //Step Size Table 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767}; public Receiver(AudioFormat format, int nInternalBufferSize, int nExternalBufferSize, //Sets Up Audio System String strMixerName)throws LineUnavailableException { Mixer mixer = null; if (strMixerName != null){ Mixer.InfomixerInfo = getMixerInfo(strMixerName); mixer = AudioSystem.getMixer(mixerInfo); } DataLine.InfosourceInfo = new DataLine.Info(SourceDataLine.class, format, nInternalBufferSize); if (mixer != null){ m_sourceLine = (SourceDataLine) mixer.getLine(sourceInfo); }else{ m_sourceLine = (SourceDataLine) AudioSystem.getLine(sourceInfo); } m_sourceLine.open(format, nInternalBufferSize); m_nExternalBufferSize = nExternalBufferSize; } public int getIndexAdjust(float multiplier){ //Returns Index Adjustment according to int adjust = -1; //the step size multiplier if(multiplier == 1.75f){ adjust = 8; }else if(multiplier == 1.5f){ adjust = 6; }else if(multiplier == 1.25f){ adjust = 4; }else if(multiplier == 1f){ adjust = 2; } return adjust; } public float getMultiplier(short Quantization){ //Returns the Step Size Multiplier if(Quantization == 0){ //According to the 4-bits received per sample return 0; }else if(Quantization == 1){ return 0.25f; }else if(Quantization == 2){ return 0.5f; }else if(Quantization == 3){ return 0.75f; }else if(Quantization == 4){ return 1.0f; }else if(Quantization == 5){ return 1.25f; }else if(Quantization == 6){ return 1.50f; }else return 1.75f; } public void start(){ //Starts the Audio Thread m_sourceLine.start(); super.start(); //Receiving and Decoding } public byte[] Decode(byte[] encoded){ //Decoding Method byte data[] = new byte[322]; //322 byte array to hold decoded samples short current; //Current Sample being computed short last; //Previous Sample short code; //4 bit sample int index = 0; //Index starts at 0 float stepMult; //Step Size Multiplier int adjust; //Index Adjustment int delta; //Sample Delta int stepSize; //Step Size int datacount = 2; boolean sign; current = encoded[0]; //the first 16-bit sound is turned into a 16-bit short current = (short)(255 & current); current = (short)(current << 8); current = (short)(current | (255 & encoded[1])); //System.out.println("FIRST CURRENT = "+current); last = current; //set last to first sample data[0] = encoded[0]; data[1] = encoded[1]; for(int i = 2; i < encoded.length; i++){ //each cycle should decode 2 16-bit sounds from a byte sign = false; datacount = (4*(i-1))-2; //formula for getting the right nodes in the data array from i code = encoded[i]; //first half of the byte code = (short)(code & 255); code = (short)(code >> 4); //shifts left half to right half code = (short)(code & 15); //assures the left half is 0's if(code > 7){ //gets the sign of the delta (positive or negative) sign = true; //if negative, sign = true code = (short)((byte)code & 7); }else{ sign = false; } stepMult = getMultiplier(code); //Uses the 4-bits to get the Step Size Multiplier adjust = getIndexAdjust(stepMult); //And the Index Adjustment stepSize = stepSizeTable[index]; //Uses the index to get the step size delta = Math.round(stepSize * stepMult);//Sets Delta if(sign){ delta *= -1; } //Sets Delta to Negative if necessary current = (short)(last + (short)delta); //Sets Current sample to sum of previous and delta data[datacount] = (byte)((current >> 8) & 255); //Splits the 16-bit short into two bytes data[datacount+1] = (byte)(current & 255); //Sets them into the array index = index + adjust; //Updates the Index if(index < 0){ index = 0; } if(index > 88){ index = 88; } last = current; //Sets Last to Current //second half of the byte code = encoded[i]; //Repeats the same thing using the code = (short)(code & 255); //right half of the byte code = (short)(code & 15); if(code > 7){ sign = true; code = (short)((byte)code & 7); }else{ sign = false; } stepMult = getMultiplier(code); adjust = getIndexAdjust(stepMult); stepSize = stepSizeTable[index]; delta = Math.round(stepSize * stepMult); if(sign){ delta *= -1; } current = (short)(last + (short)delta); data[datacount+2] = (byte)((current >> 8) & 255); data[datacount+3] = (byte)(current & 255); index = index + adjust; if(index < 0){ index = 0; } if(index > 88){ index = 88; } last = current; } return data; //Returns the decompressed data array } public void end(){ goflag = false; } public void run(){ try{ DatagramSocket serverSocket = new DatagramSocket(6001); //Opens the Receiving Socket byte[] abBuffer = new byte[82]; //Receiving array byte[] decoded = new byte[322]; //Decompressed Array m_bRecording = true; PacketsIN = 0; while (m_bRecording & goflag) { abBuffer = new byte[82]; decoded = new byte[322]; DatagramPacket receivePacket = new DatagramPacket(abBuffer,82); //Creates the Packet serverSocket.receive(receivePacket); //Fills it from Server decoded = Decode(receivePacket.getData()); //Decoded the packet's Data m_sourceLine.write(decoded, 0, decoded.length); //And writes the data to the PacketsIN++; } //audio out line }catch(Exception e){ System.out.println("Receiving Error"); System.exit(1); } } private static Mixer.Info getMixerInfo(String strMixerName){ //Mixer Info for Mixer.Info[]aInfos = AudioSystem.getMixerInfo(); //Setting up the audio system for (int i = 0; i < aInfos.length; i++){ if (aInfos[i].getName().equals(strMixerName)){ return aInfos[i]; } } return null; } public static void main(String[] args) throws Exception { StringstrMixerName = null; floatfFrameRate = 8000.0F; //8000 samples per sec int nInternalBufferSize = DEFAULT_INTERNAL_BUFSIZ; //sets audio buffers int nExternalBufferSize = DEFAULT_EXTERNAL_BUFSIZ; goflag = true; AudioFormataudioFormat = new AudioFormat(fFrameRate, 16, 1, true, true);//sets audio format //8000 samples per second on Signed PCM and bigEndian format Receiver audioLoop = null; long start = System.currentTimeMillis()/1000; try{ audioLoop = new Receiver(audioFormat, nInternalBufferSize,nExternalBufferSize,//sets the audio system up strMixerName); }catch (LineUnavailableException e){ e.printStackTrace(); System.exit(1); } audioLoop.start(); //Starts the Receiving Thread, and Decoding and Audio try{ InputStreamReader input = new InputStreamReader(System.in); while(input.read() < 0){} audioLoop.end(); System.out.println("Packets received = "+PacketsIN); System.out.println("Samples received = "+(PacketsIN*161)); System.out.println("Time Elapsed = "+((System.currentTimeMillis()/1000) - start)); System.out.println("Packets Per Second = "+(PacketsIN / ((System.currentTimeMillis()/1000) - start))); }catch(IOException e){} System.exit(1); } } ************************************************************************ Sender.java ************************************************************************ import java.io.*; import javax.sound.sampled.*; import java.net.*; import java.util.*; public class Sender extends Thread{ private static final intDEFAULT_INTERNAL_BUFSIZ = 20480; //Audio Buffer Sizes private static final intDEFAULT_EXTERNAL_BUFSIZ = 20480; private TargetDataLinem_targetLine; //Audio In Line private booleanm_bRecording; private intm_nExternalBufferSize; static int PacketsOUT; static boolean goflag; int stepSizeTable[] = { 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 19, 21, 23, 25, 28, 31, 34, 37, 41, 45, 50, 55, 60, 66, 73, 80, 88, 97, 107, 118, 130, 143, 157, 173, 190, 209, 230, 253, 279, 307, 337, 371, 408, 449, 494, 544, 598, 658, 724, 796, 876, 963, 1060, 1166, 1282, 1411, 1552, 1707, 1878, 2066, 2272, 2499, 2749, 3024, 3327, 3660, 4026, 4428, 4871, 5358, 5894, 6484, 7132, 7845, 8630, 9493, 10442, 11487, 12635, 13899, 15289, 16818, 18500, 20350, 22385, 24623, 27086, 29794, 32767}; public Sender(AudioFormat format, int nInternalBufferSize, int nExternalBufferSize, //Gets Lines and Mixers String strMixerName) throws LineUnavailableException { //Ready Mixer mixer = null; if (strMixerName != null){ Mixer.InfomixerInfo = getMixerInfo(strMixerName); mixer = AudioSystem.getMixer(mixerInfo); } DataLine.InfotargetInfo = new DataLine.Info(TargetDataLine.class, format, nInternalBufferSize); if (mixer != null){ m_targetLine = (TargetDataLine) mixer.getLine(targetInfo); }else{ m_targetLine = (TargetDataLine) AudioSystem.getLine(targetInfo); } m_targetLine.open(format, nInternalBufferSize); m_nExternalBufferSize = nExternalBufferSize; } public int getIndexAdjust(float multiplier){ //Returns the Index Adjustment int adjust = -1; //According to the step size multiplier if(multiplier == 1.75f){ adjust = 8; }else if(multiplier == 1.5f){ adjust = 6; }else if(multiplier == 1.25f){ adjust = 4; }else if(multiplier == 1f){ adjust = 2; } return adjust; } public float[] getMultiplier(int sample, int stepSize){ //returns Step Size Multiplier int absSample = Math.abs(sample); //AND Quantization Output as a float float array[] = new float[2]; //it's cast to a byte later if(absSample < (.25 * stepSize)){ array[0] = 0; array[1] = 0; }else if(absSample < (.5 * stepSize)){ array[0] = 0.25f; //returns Multiplier array[1] = 1; //and Quantization Output }else if(absSample < (.75 * stepSize)){ array[0] = 0.5f; array[1] = 2; }else if(absSample < stepSize){ array[0] = 0.75f; array[1] = 3; }else if(absSample < (1.25 * stepSize)){ array[0] = 1f; array[1] = 4; }else if(absSample < (1.5 * stepSize)){ array[0] = 1.25f; array[1] = 5; }else if(absSample < (1.75 * stepSize)){ array[0] = 1.5f; array[1] = 6; }else{ array[0] = 1.75f; array[1] = 7; } return array; } public byte[] Encode(byte[] data){ //takes the audio buffer and returns ten encoded packets byte encoded[] = new byte[82]; //will contain the encoded values int encodeCount = 2; int delta; int stepSize = 0; float[] stepMult; short Quant; int adjust; //index adjustment int index = 0; //Index starts at 0 short last = 0; //contains the previous 16-bit value (sent value, not original) short current = 0; //contains the current 16-bit value byte newbyte = 0; boolean sign; encoded[0] = data[0]; //the first 16-bit sound is not encoded encoded[1] = data[1]; current = data[0]; //the first 16-bit sound is turned into a 16-bit short current = (short)(255 & current); current = (short)(current << 8); current = (short)(current | (255 & data[1])); last = current; for(int i = 2; i< data.length; i+=2){ //the next 160 16-bit sounds are encoded into 4-bits current = 0; //each will share a byte with another sound. current = data[i]; current = (short)(255 & current); current = (short)(current << 8); current = (short)(current | (255 & data[i+1])); delta = (current - last); sign = true; //true means greater than 0 if(delta < 0){ sign = false; //false means less than 0, gets appended to Quant } delta = Math.abs(delta); //Absolute value of Delta stepSize = stepSizeTable[index]; //Gets the Step Size stepMult = getMultiplier(delta,stepSize); //Multiplier adjust = getIndexAdjust(stepMult[0]); //Index Adjustment index = index + adjust; //Makes adjustment to index if(index < 0){ index = 0; } if(index > 88){ index = 88; } delta = Math.round(stepSize * stepMult[0]); //Gets the New Delta Value if(!sign){ delta *= -1; } //Makes it negative if necessary last = (short)(last +(short)(delta)); //Save value as LAST Quant = (short)stepMult[1]; //Set Quant as computer Quantization Output if(!sign){ Quant = (short)((byte)Quant | 8); //Makes 4th bit 1, if negative } if((i%4)==2){ //if it's even, shifts to right and stored encoded[encodeCount] = (byte)((Quant & 255) << 4); }else{ //if it's odd, OR with the previous value encoded[encodeCount] = (byte)(encoded[encodeCount] | (255 & Quant)); encodeCount++; //thus, two 4-bit values are stored in one byte } } return encoded; //return ENCODED array } public void start(){ //Starts the Audio In Thread m_targetLine.start(); super.start(); } public void end(){ goflag = false; } public void run() { try{ byte[] abBuffer = new byte[322]; //buffer size of 161 2-byte samples byte[] sendData = new byte[82]; //buffer size of 160 4-bit samples and 1 16-bit sample m_bRecording = true; DatagramSocket clientSocket = new DatagramSocket();//Starts the Sending Socket InetAddress IPAddress = InetAddress.getByName("localhost"); //Sets The IP ADDRESS PacketsOUT = 0; while (m_bRecording && goflag) { abBuffer = new byte[322]; sendData = new byte[82]; m_targetLine.read(abBuffer, 0, 322); //Read in the samples sendData = Encode(abBuffer); //Encode the samples DatagramPacket sendPacket = new DatagramPacket(sendData,82,IPAddress,6001); //Send the Encoded Samples clientSocket.send(sendPacket); //161 samples as 82 bytes PacketsOUT++; Thread.sleep(20); //Wait 20 milliseconds before sending again } clientSocket.close(); //Close Socket }catch(Exception e){ //Try and Catch required for Thread.sleep() System.out.println("error"); } } private static Mixer.Info getMixerInfo(String strMixerName){ //Returns Mixer info Mixer.Info[]aInfos = AudioSystem.getMixerInfo(); //Used for setting up the Audio System for (int i = 0; i < aInfos.length; i++){ if (aInfos[i].getName().equals(strMixerName)){ return aInfos[i]; } } return null; } public static void main(String[] args){ StringstrMixerName = null; floatfFrameRate = 8000.0F; //8000 samples per second int nInternalBufferSize = DEFAULT_INTERNAL_BUFSIZ; int nExternalBufferSize = DEFAULT_EXTERNAL_BUFSIZ; AudioFormataudioFormat = new AudioFormat(fFrameRate, 16, 1, true, true); SenderaudioLoop = null; goflag = true; long start = System.currentTimeMillis()/1000; try{ audioLoop = new Sender(audioFormat, nInternalBufferSize,nExternalBufferSize, //Sets up the Audio System strMixerName); }catch (LineUnavailableException e){ e.printStackTrace(); System.exit(1); } audioLoop.start(); //Starts the Thread try{ InputStreamReader input = new InputStreamReader(System.in); while(input.read() < 0){} audioLoop.end(); System.out.println("Packets sent = "+PacketsOUT); System.out.println("Samples sent = "+(PacketsOUT*161)); System.out.println("Time Elapsed = "+((System.currentTimeMillis()/1000) - start)); System.out.println("Packets Per Second = "+(PacketsOUT / ((System.currentTimeMillis()/1000) - start))); }catch(IOException e){} System.exit(1); } }
|
 |
Jose Botella
Ranch Hand
Joined: Jul 03, 2001
Posts: 2120
|
|
Welcome to the Ranch omer. Have you considered JMF? Specially because it provides an implementation of the Realtime Transport Protocol. This protocol transmits voice over the net at time Look at an example here [ April 23, 2004: Message edited by: Jose Botella ]
|
SCJP2. Please Indent your code using UBB Code
|
 |
Vijay Arora
Greenhorn
Joined: May 11, 2004
Posts: 4
|
|
Hi omer, i hv tried to run ur code but weh i m running Sender.java it is giving me error msg "java.io.IOException The handle is invalid." why it is giving this message? i hv windows 2000 server and JDK 1.4 plz help me out. This code is very usefull 4 me. thanx in advance.
|
 |
 |
|
|
subject: Voice Chat Open Source
|
|
|
|