Google Multiplayer RealTime socket streams - android

I wonder if someone used RealTime sockets with Google Multiplayer (rather than messages).
I have a code that works OK with streams derived from "native"(IP) socket, so I expected it to work with RealTime socket streams too. Unfortunately this is not the case.
The following code works fine with RealTime sockets
Sending end:
int s1, s2;
os.write(new byte[] {(byte)s1, (byte)s2};
os.flush(); // May be redundant, according to Google docs
Receiving end:
byte[] buffer = new byte[2];
is.read(buffer);
int r1=buffer[0] & 0xff;
int r2=buffer[1] & 0xff;
However, since the length of chuck is unknown in advance, I prefer to spit the chunk into two pieces: length and the data, read one after another. Consider therefore a different code:
Sending end:
byte s1, s2;
os.write(s1);
os.write(s2);
os.flush();
Receiving end:
int r1=is.read();
int r2=is.read();
In this case, only first byte is read, while the second byte never comes!
Since Android docs don't recommend flush, I tried to make a wrapper for caching several writes into one on flush:
public class OutputStreamWrapper extends OutputStream {
private OutputStream innerOs;
private ByteArrayOutputStream baos;
public OutputStreamWrapper(OutputStream innerOs) {
this.innerOs = innerOs;
baos = new ByteArrayOutputStream();
}
#Override
public void write(int oneByte) throws IOException {
baos.write(oneByte);
}
#Override
public void flush() throws IOException {
if (baos.size() > 0)
innerOs.write(baos.toByteArray());
baos.reset();
}
#Override
public void write(byte[] buffer, int offset, int count)
throws IOException {
baos.write(buffer, offset, count);
}
#Override
public void close() throws IOException {
flush();
innerOs.close();
baos.close();
}
}
The problem persists!
Am I doing something wrong?
If I can't find the solution, I will have to write custom streams as wrappers for Real-Time Messages, but it is really a shame to avoid "ready to use" streams.

No answer for two months... Have to answer it somehow :)
I tried several approaches, but couldn't get it working. Either the implementation of RealTime sockets is broken (BTW, I haven't come across any example of using those), or I still misunderstand something.
As a result, I found nothing better than making my own RealTime sockets by sending messages (reliable or unreliable, depending on request) under the hood.
The code is so weird that I am ashamed to publish it. But this is the idea:
outputStream has a BiteArrayOuputStream of size equals to max allowed size of RealTimeMessage.
It fires a message either on flush() or when the array is full. There is an indicator of a split packet.
I keep a queue of received messages. The input streams polls the queue and after the whole packet has been collected it returns the bytes.
Works great for me!

Related

OkHttp Http2 Audio stream, Can I control sent bytes?

I am trying to send audio stream using OkHttp following example presented here,
But the problem is if I am using pipe I have no control over how bytes are sent to the server, and this is causing some interruption in the audio because server is sensitive to the bytes flow.
Listening to the port I saw that using Pipe I send wrong chunk sizes
Expected:
4,
626,
4,
1255,
4,
1091,
Reality:
1460,
1460,
1460,
2109,
1460
Is there a way to manipulate how data is sent using PipeBody? tried to add Thread.sleep and flush() between sink.write(data) but didn't see any changes.
You need to flush more often in the code that accepts pipe data and sends it on the HTTP request.
Replace this:
#Override public void writeTo(BufferedSink sink) throws IOException {
sink.writeAll(pipe.source());
}
With this:
#Override public void writeTo(BufferedSink sink) throws IOException {
sink.writeAllFrequentFlush(pipe.source());
}
Then write a function that flushes at every opportunity. This one is derived from the Okio writeAll function.
fun BufferedSink.writeAllFrequentFlush(source: Source): Long {
var totalBytesRead = 0L
while (true) {
val readCount: Long = source.read(buffer, 8192L)
if (readCount == -1L) break
totalBytesRead += readCount
emit()
}
return totalBytesRead
}

Android USB host : interrupt do not respond immedietly

I have a usb device which have a button.
And I want to an android app to catch a signal of the button.
I found inferface and endpoint number of the button.
It had seemed to perform ordinarily at galaxy S3 and galaxy note.
But later, I found that it has delay at other phones.
I was able to receive instant responses about 10% of the time; usually there was a 2-second delay, with some cases where the whole response was lost.
Although I couldn't figure out the exact reason, I realized that the phones that had response delays were those with kernel version 3.4 or later.
Here is the code that I used initially.
if(mConnection != null){
mConnection.claimInterface(mInterfaces.get(0), true);
final UsbEndpoint endpoint = mInterfaces.get(0).getEndpoint(0);
Thread getSignalThread = new Thread(new Runnable() {
#Override
public synchronized void run() {
byte[] buffer = new byte[8];
final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
while(mConnection!=null){
int len = mConnection.bulkTransfer(endpoint, buffer, buffer.length, 0);
if( len>=0 ){
// do my own code
}
}
}
});
getSignalThread.setPriority(Thread.MAX_PRIORITY);
getSignalThread.start();
}
edit timeout
when the timeout was set to 50ms, I wasn't able to receive responses most of the time. When the timeout was 500ms, I was able to initially get some delayed-responses; however, I lost all responses after several tries with this setting.
Using UsbRequest
In addition to using the bulktransfer method, I also tried using UsbRequest and below is the code that I used.
#Override
public synchronized void run() {
byte[] buffer = new byte[8];
final ByteBuffer byteBuffer = ByteBuffer.wrap(buffer);
UsbRequest inRequest = new UsbRequest();
inRequest.initialize(mConnection, endpoint);
while(mConnection!=null){
inRequest.queue( byteBuffer , buffer.length);
if( mConnection.requestWait() == inRequest ){
// do my own code
}
}
}
However, the same kind of delay happened even after using UsbRequest.
Using libusb
I also tried using libusb_interrupt_transfer from an open source library called libusb.
However this also produced the same type of delay that I had when using UsbDeviceConnection.
unsigned char data_bt[8] = { 0, };
uint32_t out[2];
int transfered = 0;
while (devh_usb != NULL) {
libusb_interrupt_transfer(devh_usb, 0x83, data_bt, 8, &transfered, 0);
memcpy(out, data_bt, 8);
if (out[0] == PUSH) {
LOGI("button pushed!!!");
memset(data_bt, 0, 8);
//(env)->CallVoidMethod( thiz, mid);
}
}
After looking into the part where libusb_interrupt_transfer is processed libusb, I was able to figure out the general steps of interrupt_transfer:
1. make a transfer object of type interrupt
2. make a urb object that points to the transfer object
3. submit the urb object to the device's fd
4. detect any changes in the fd object via urb object
5. read urb through ioctl
steps 3, 4, 5 are the steps regarding file i/o.
I was able to find out that at step 4 the program waits for the button press before moving onto the next step.
Therefore I tried changing poll to epoll in order to check if the poll function was causing the delay; unfortunately nothing changed.
I also tried setting the timeout of the poll function to 500ms and making it always get values of the fd through ioctl but only found out that the value changed 2~3 seconds after pressing the button.
So in conclusion I feel that there is a delay in the process of updating the value of the fd after pressing the button. If there is anyone who could help me with this issue, please let me know. Thank you.
Thanks for reading

Interrupt HttpURLConnection request Android

I am creating simple class which sends requests using HttpURLConnection to server and receive responses. I want to add interrupt() method which interrupt current request (imagine request is running in AsyncTask and interrupt() is called from main thread). There are 2 processes which takes a lot of time and I don't know how to interrupt them:
writing to output stream
reading from input stream
So let's say that I want to for example interrupt reading from input stream which I read like this:
downloadThread = new Thread(new Runnable() {
#Override
public void run() {
try {
buffer = readFully(connection.getInputStream());
} catch( Exception e ) {
e.printStackTrace();
}
}
});
downloadThread.start();
And readFully() method is:
public byte[] readFully(InputStream input) throws IOException {
byte[] buffer = new byte[8192];
int bytesRead;
ByteArrayOutputStream output = new ByteArrayOutputStream();
while ((bytesRead = input.read(buffer)) != -1) {
output.write(buffer, 0, bytesRead);
}
return output.toByteArray();
}
How can I stop reading from input stream (in other words, downloading) ?
stop() method of Thread is deprecated and cannot be used. There are written everywhere that I should regularly check if thread should be stopped and stop it manually. But how can I do that when whole time takes this line (If I understand well):
connection.getInputStream()
I think this is the same kind of question but it is unanswered (see comments of solution):
How to stop HttpURLConnection connect on Android
Please, don't refer me to some REST library. I would really like to know how to handle this issue. Thanks ;).
connection.getInputStream() will return as soon as a connection is established with the server and the client is ready to start streaming the response.
So it depends on the connection: if you're e.g. downloading a large file, then most (nearly all) of the time should be spent inside the readFully() method while it is streamed, while if the response is extremely short of empty then readFully() will do very little.
In the first case, the easiest way to "interrupt" is to set a boolean flag and check it inside the loop.
while ((bytesRead = input.read(buffer)) != -1)
{
if (cancelled)
return null;
output.write(buffer, 0, bytesRead);
}
This "boolean flag" can be the isCancelled() method if you're implementing this inside an AsyncTask's doInBackground() (recommended).
In the second case, there's not much you can do, short of killing the thread outright (not recommended at all).
I think it would be better to implement it using Android AsyncTask class.
http://developer.android.com/reference/android/os/AsyncTask.html#cancel(boolean)
There is a method cancel() there and also isCancelled() which you could use to check if the task was cancelled and exit the InputStream reading loop.

Byte Dropped Over Bluetooth Connection in Android

I am having some issues with bytes being dropped over a bluetooth connection between an android device (Gingerbread 2.3.1) and a PC. The way I receiving the data is in a 2 byte buffer. The values being received is streaming from the PC over a few minutes (values represent a waveform). Here are just a few snippets of code so you can get the idea. The base of my code is from the android bluetooth chat sample code.
BluetoothSocket socket;
...
mmInStream=socket.getInputStream;
...
byte[] buffer= new byte[2];
...
bytes = mmInStream.read(buffer);
Has anyone has issues with this type of thing? The dropped bytes seem to happen at random times while at other times the values received are as expected. I am using a 2 byte buffer because the values I am receiving are 16 bit signed integers. From the PC side of things I am using RealTerm to send the binary files of data.
Is it possible that my buffer is too small and that is causing the dropped bytes?
Thanks
Following up to your answer. You could just use a counter to remember how many bytes already read and compare it to the number wanted and also use it for the index to write the next byte(s). See a C# version at http://www.yoda.arachsys.com/csharp/readbinary.html
public static void ReadWholeArray (Stream stream, byte[] data)
{
int offset=0;
int remaining = data.Length;
while (remaining > 0)
{
int read = stream.Read(data, offset, remaining);
if (read <= 0)
throw new EndOfStreamException
(String.Format("End of stream reached with {0} bytes left to read", remaining));
remaining -= read;
offset += read;
}
}
I have found what the issue is. I want to thank alanjmcf for pointing me in the right direction.
I wasn't checking by bytes variable to see how many bytes were returned from the mmInStream.read(buffer). I was simply expecting that every buffer returned would contain 2 bytes. The way i solved the issue was with the following code after getting the buffer back from the InputStream:
//In the case where buffer returns with only 1 byte
if(lagging==true){
if(bytes==1){
lagging=false;
newBuf=new byte[] {laggingBuf, buffer[0]};
ringBuffer.store(newBuf);
}else if(bytes==2){
newBuf=new byte[] {laggingBuf, buffer[0]};
laggingBuf=buffer[1];
ringBuffer.store(newBuf);
}
}else if(lagging==false){
if(bytes==2){
newBuf = buffer.clone();
ringBuffer.store(newBuf);
}else if(bytes==1){
lagging=true;
laggingBuf=buffer[0];
}
}
This fixed my problem. Any suggestions on a better methodology?

Transferring large amounts of data over bluetooth on Android Gingerbread

I'm trying to transfer about a megabyte of arbitrary data at a time from one android phone to another. Currently, I write the size, a command code and the data to a DataOutputStream around a BufferedOutputStream, around the OutputStream returned from bluetoothSocketInstance.getOutputStream().
The receiving phone reads the size and command code and then reads from the input stream until it has gotten all the data it is expecting. This works for short strings, but for larger files not all the data is transferred. Running the app in the debugger shows that the write returns without any exceptions and the read reads a fraction of the bytes expected and then blocks indefinitely. It also does not throw any exceptions.
Is there a buffer somewhere that is filling up? Is there something else I need to do to ensure that all the data gets transferred?
My code for the sender and receiver are below:
Sender:
try {
DataOutputStream d = new DataOutputStream(new BufferedOutputStream(mmOutStream,buffer.length+8));
//int b= buffer.length;
d.writeInt(buffer.length);
d.writeInt(command);
d.write(buffer);
d.flush();
} catch (IOException e) {
Log.e(TAG, "Exception during write", e);
}
}
Receiver:
try {
// Read from the InputStream
int messageSize= inStream.readInt();
int messageCode = inStream.readInt();
bytes=0;
buffer =new byte[messageSize];
while(bytes < messageSize)
{
bytes += inStream.read(buffer,bytes,messageSize - bytes);
}
message = bytes;
} catch (IOException e) {
Log.e(TAG, "disconnected", e);
connectionLost();
break;
}
After some more testing on my end, I changed my sending code to look like this:
for(int i=0; i<buffer.length;i+=BIG_NUM)
{
int b = ((i+BIG_NUM) < buffer.length) ? BIG_NUM: buffer.length - i;
d.write(buffer,i,b);
d.flush();
}
The files now get sent. Does anyone have an idea why? Does the call to flush() block until the data has actually been transferred? Is there any documentation about the size of the send and receive buffers that would help me to decide how large I can safely make BIG_NUM?
I have similar problem, when sending file there are some parts missing. I try BufferedOutputStream but problem still exist.
Finally i find simple solution:
You don't need to send buffer length, just split sending buffer to byte array (for example [8192]) and on receive side make sure that this buffer is much bigger about 4 or 8 times than sending buffer. This worked for me and file is sent completed.

Categories

Resources