send a big byte array through java socket - java

I have a big byte array of length more than 1200000. I want to send it by DataOutputStream, and receive at client by DataInputStream.
I'm using the code
out.write(outData)
in.readFully(inData)
out is DataOutputStream, in is DataInputStream, outData is the byte array I want to send.
When I run the program, if the length of byte array is around 120000, the array can be sent, but when the length becomes 1200000, the server cant receive the array. Should I split the big array into some small ones?
I tried such code below, but it still not working.
out.writeInt(outData.length);
int start = 0;
int len = 0;
int count = outData.length;
while (count > 0) {
if (count < 4096)
len = count;
else len = 4096;
out.write(outData, start, len);
start += len;
count -= len;
}
and
int length=in.readInt();
byte[] inData=new byte[length];
in.readFully(inData);
Can somebody help? Thanks.

In writer:
for(int i=0;i<length;i++){
dataoutputstream.writeByte(bytearray[i]);
}
In reader:
for(int i=0;i<length;i++){
bytearray[i]=datainputstream.readByte();
}

Related

Mix byte array android

I would like to mix audio byte array, but I didn't succeed to sum the array.(note i already added some silent bytes of 0 as padding before).
I have an ArrayList of byte[] which contains:
the first byte[] is header (44 bytes).
Following byte[] are raw data byte array to be mixed
Here is my code:
ArrayList<byte[]> ListAudio = new ArrayList<byte[]>();
byte[] header= WriteHeader(); //wav header 44 bytes
ListAudio.add(header);
for (byte[] b : audioTreatment.ListDataByte) {
ListAudio.add(b);
}
//calculate total length of audio
int length = 0;
for (byte[] array : ListAudio) {
length += array.length;
}
final int len = length;
final byte[] mixBytes = new byte[len];
for (byte[] array : ListAudio) {
for (int i = 44; i < len; ++i) {
mixBytes[i] += array[i];
// mixBytes[i]=(byte) ((bytes1[i]+bytes2[i]) / 2);
}
}
I found somewhere that the method to mix digital byte array is :
mixBytes[i]=(byte) ((bytes1[i]+bytes2[i]) / 2);
I don't arrive to include the calcul above, to sum the byte array.
How can i sum the bytes array from my ArrayList ?
you have to declare your sources to merge them
byte[] source1 = ListAudio.get(0); //first from list
byte[] source2 = ListAudio.get(1); //second from list
int length = Math.min(source1.length, source2.length);//length of new array
length = length - 44; //skipping 44 byte
byte[] dest = new byte[length];
for(int index = 0; index < length; index ++){
byte b1 = source1[index+44];
byte b2 = source2[index+44];
dest[index] = (byte) ((b1+b2) / 2);
}
That would merge the first two byte[] from your list.
If you want to merge other sources you can change them by selecting other byte[] from your List.
HINT
The length of the destination is declared as Math.min(a,b) but you can fill missing bytes with zeros if you want...
if you want to merge all arrays, you have to adjust your merge operation
mixing two bytes: mixBytes[i]=(byte) ((bytes1[i]+bytes2[i]) / 2);
mixing three bytes: mixBytes[i]=(byte) ((bytes1[i]+bytes2[i]+bytes3[i]) / 3);
mixing N bytes: mixBytes[i]=(byte) ((bytes1[i]+bytes2[i]+bytes3[i]+...+bytesN[i]) / N);
ok, for your code snipped it would be:
int length = ...;//length of result, either min or max as mentioned above, see HINT
byte[] mixBytes = new byte[length];
int amountAudio = ListAudio.size(); //amount of tracks in your list aka 'N'
int sum;
for(int index = 0; index < length; index++){
sum = 0;
for(byte[] source: ListAudio){
//adding all byte into one big integer
sum = sum + source[index]; //NOTE: watch for indexOutOfBoundsException
}
//afterward divide the big int through amount of Audio tracks in your list
mixBytes[index] = (byte)(sum / amountAudio);
}

Send array (not array list) through UDP

i have array like this in client side
int arr[] = new int[]{1, 6, 3, 2, 9};
how i can send it to SERVER through UDP ? and how i can read it in SERVER side?
Convert the array to an byte array, then send the byte array. The receiver converts the byte array back to an int[];
You can use the class DataOutputStream to create the byte array.
ByteArrayOutputStream bos = new ByteArrayOutputStream();
DataOutputStream dos = new DataOutputStream(bos);
int len = 0;
in protokollVersion = 1;
// Write a version, in case you want to change your format later, such that
// the receiver has a chance to detect which format version is used.
dos.writeInt(protokollVersion);
if (arr != null) {
len = arr.length;
}
dos.writeInt(arr.length);
for (int i = 0; i < len; i++) {
dos.writeInt(arr[i]);
}
dos.close();
byte[] bytes = bos.getBytes();
On the receiver side, read the byte array using DataInputStream(byte[] bytes) and DataInputStream.readInt().

Read 32 bit binary numbers in java

I am trying to read five 32-bit binary numbers and print them as int. Here is my code:
FileInputStream fin = new FileInputStream(file);
int count = 5;
for (int i = 0; i < count; i++) {
byte[] input = file.getBytes();
String bin=Integer.toBinaryString(0xFF & input[i] | 0x100).substring(1);
System.out.println(bin);
I am getting this:
01010011
01101110
00110011
01011111
01010010
What am I doing wrong? thanks
You're not actually reading from the file, but printing the binary representation of the first five characters of the name of the file. Use fin.read() to read bytes from the file.
You can also use DataInputStream to read 32 bit big endian integers directly, instead of reading them as 4 individual bytes.
If you need to read five big-endian 32-bit integers, then I suggest that you use DataInputStream, e.g.
final int count = 5;
try (DataInputStream dis = new DataInputStream(new FileInputStream(file))) {
for (int i = 0; i < count; i++) {
int value = dis.readInt();
System.out.println(Integer.toBinaryString(value));
}
}

Converting array with samples into byte array

I have two-dimensional array of integers. First index indicates the number of channels. The second one indicates the number of sample in the channel. How can I save this array into the audio file? I know, I have to convert it to byte array, but I have no idea how to do that.
// edit
More info. I already have a class for drawing a waveform. It is here:
http://javafaq.nu/java-example-code-716.html
now I want to cut part of this wave and save it to the new file. So I have to cut part of int[][] samplesContainer, convert it to byte array (I don't know how) and then save it to file with the same format as audioInputStream.
// edit
OK. So the biggest problem is to write inverted function to this one:
protected int[][] getSampleArray(byte[] eightBitByteArray) {
int[][] toReturn = new int[getNumberOfChannels()][eightBitByteArray.length / (2 * getNumberOfChannels())];
int index = 0;
//loop through the byte[]
for (int t = 0; t < eightBitByteArray.length;) {
//for each iteration, loop through the channels
for (int a = 0; a < getNumberOfChannels(); a++) {
//do the byte to sample conversion
//see AmplitudeEditor for more info
int low = (int) eightBitByteArray[t];
t++;
int high = (int) eightBitByteArray[t];
t++;
int sample = (high << 8) + (low & 0x00ff);
if (sample < sampleMin) {
sampleMin = sample;
} else if (sample > sampleMax) {
sampleMax = sample;
}
//set the value.
toReturn[a][index] = sample;
}
index++;
}
return toReturn;
}
I don't understand why there is second incrementation of t, after high. I also have no idea how can i get high and low from sample.
The code you posted reads a sample stream, byte by byte, into the samples array. The code assumes that, in the stream, every two 8-bit bytes form a 16-bit sample, and that there is one sample for each of the NumOfChannels channels.
So, given an array of samples like the one returned by that code,
int[][] samples;
and a byte array for streaming,
byte[] stream;
you might build the converse stream of bytes this way
for (int i=0; i<NumOfSamples; i++) {
for (int j=0; j<NumOfChannels; j++) {
int sample=samples[i][j];
byte low = (byte) (sample & 0xff) ;
byte high = (byte) ((sample & 0xff00 ) >> 8);
stream[((i*NumOfChannels)+j)*2] = low;
stream[(((i*NumOfChannels)+j)*2)+1] = high;
}
}

Fast reading of little endian integers from file

I need to read a binary file consisting of 4 byte integers (little endian) into a 2D array for my Android application. My current solution is the following:
DataInputStream inp = null;
try {
inp = new DataInputStream(new BufferedInputStream(new FileInputStream(procData), 32768));
}
catch (FileNotFoundException e) {
Log.e(TAG, "File not found");
}
int[][] test_data = new int[SIZE_X][SIZE_Y];
byte[] buffer = new byte[4];
ByteBuffer byteBuffer = ByteBuffer.allocate(4);
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(buffer);
byteBuffer = ByteBuffer.wrap(buffer);
test_data[j][SIZE_Y - i - 1] = byteBuffer.order(ByteOrder.LITTLE_ENDIAN).getInt();
}
}
This is pretty slow for a 2k*2k array, it takes about 25 seconds. I can see in the DDMS that the garbage collector is working overtime, so that is probably one reason for the slowness.
There has to be a more efficient way of using the ByteBuffer to read that file into the array, but I'm not seeing it at the moment. Any idea on how to speed this up?
Why not read into a 4-byte buffer and then rearrange the bytes manually? It will look like this:
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(buffer);
int nextInt = (buffer[0] & 0xFF) | (buffer[1] & 0xFF) << 8 | (buffer[2] & 0xFF) << 16 | (buffer[3] & 0xFF) << 24;
test_data[j][SIZE_Y - i - 1] = nextInt;
}
}
Of course, it is assumed that read reads all four bytes, but you should check for the situation when it's not. This way you won't create any objects during reading (so no strain on the garbage collector), you don't call anything, you just use bitwise operations.
If you are on a platform that supports memory-mapped files, consider the MappedByteBuffer and friends from java.nio
FileChannel channel = new RandomAccessFile(procData, "r").getChannel();
MappedByteBuffer map = channel.map(FileChannel.MapMode.READ_ONLY, 0, 4 * SIZE_X * SIZE_Y);
map.order(ByteOrder.LITTLE_ENDIAN);
IntBuffer buffer = map.asIntBuffer();
int[][] test_data = new int[SIZE_X][SIZE_Y];
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
test_data[j][SIZE_Y - i - 1] = buffer.get();
}
}
If you need cross-platform support or your platform lacks memory-mapped buffers, you may still want to avoid performing the conversions yourself using an IntBuffer. Consider dropping the BufferedInputStream, allocating a larger ByteBuffer yourself and obtaining a little-endian IntBuffer view on the data. Then in a loop reset the buffer positions to 0, use DataInputStream.readFully to read the large regions at once into the ByteBuffer, and pull int values out of the IntBuffer.
First of all, your 'inp.read(buffer)' is unsafe, as read contract does not guarantee that it will read all 4 bytes.
That aside, for quick transformation use the algorithm from DataInputStream.readInt
I've adapted for you case of byte array of 4 bytes:
int little2big(byte[ ] b) {
return (b[3]&0xff)<<24)+((b[2]&0xff)<<16)+((b[1]&0xff)<<8)+(b[0]&0xff);
}
I don't think it is necessary to reinvent the wheel and perform the byte reordering for endianness again. This is error prone and there is a reason a class like ByteBuffer exists.
Your code can be optimized in the sense that it wastes objects. When a byte[] is wrapped by a ByteBuffer the buffer adds a view, but the original array remains the same. It does not matter wheather the original array is modified/read from directly or the ByteBuffer instance is used.
Therefore, you only need to initialize one instance of ByteBuffer and also have to set the ByteOrder once.
To start again, just use rewind() to set the counter again to the beginning of the buffer.
I have taken your code and modified it as desribed. Be aware that it does not check for errors if there are not enough bytes in the input left. I would suggest to use inp.readFully, as this will throw EOFException if not enough bytes to fill the buffer are found.
int[][] test_data = new int[SIZE_X][SIZE_Y];
ByteBuffer byteBuffer = ByteBuffer.wrap(new byte[4]).order(ByteOrder.LITTLE_ENDIAN);
for (int i=0; i < SIZE_Y; i++) {
for (int j=0; j < SIZE_X; j++) {
inp.read(byteBuffer.array());
byteBuffer.rewind();
test_data[j][SIZE_Y - i - 1] = byteBuffer.getInt();
}
}

Categories