Implement bulk read and writes for Bluetooth sockets.
Before: 0.1 kB/s After: 100 kB/s (in my java BT speed test app)
This commit is contained in:
@@ -24,7 +24,6 @@ import java.io.InputStream;
|
||||
*
|
||||
* Used to write to a Bluetooth socket.
|
||||
*
|
||||
* TODO: Implement bulk writes (instead of one byte at a time).
|
||||
* @hide
|
||||
*/
|
||||
/*package*/ final class BluetoothInputStream extends InputStream {
|
||||
@@ -54,9 +53,46 @@ import java.io.InputStream;
|
||||
* @return the byte read or -1 if the end of stream has been reached.
|
||||
* @throws IOException
|
||||
* if the stream is closed or another IOException occurs.
|
||||
* @since Android 1.0
|
||||
* @since Android 1.5
|
||||
*/
|
||||
public int read() throws IOException {
|
||||
return mSocket.readNative();
|
||||
byte b[] = new byte[1];
|
||||
int ret = mSocket.readNative(b, 0, 1);
|
||||
if (ret == 1) {
|
||||
return (int)b[0];
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads at most {@code length} bytes from this stream and stores them in
|
||||
* the byte array {@code b} starting at {@code offset}.
|
||||
*
|
||||
* @param b
|
||||
* the byte array in which to store the bytes read.
|
||||
* @param offset
|
||||
* the initial position in {@code buffer} to store the bytes
|
||||
* read from this stream.
|
||||
* @param length
|
||||
* the maximum number of bytes to store in {@code b}.
|
||||
* @return the number of bytes actually read or -1 if the end of the stream
|
||||
* has been reached.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if {@code offset < 0} or {@code length < 0}, or if
|
||||
* {@code offset + length} is greater than the length of
|
||||
* {@code b}.
|
||||
* @throws IOException
|
||||
* if the stream is closed or another IOException occurs.
|
||||
* @since Android 1.5
|
||||
*/
|
||||
public int read(byte[] b, int offset, int length) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("byte array is null");
|
||||
}
|
||||
if ((offset | length) < 0 || length > b.length - offset) {
|
||||
throw new ArrayIndexOutOfBoundsException("invalid offset or length");
|
||||
}
|
||||
return mSocket.readNative(b, offset, length);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,7 +24,6 @@ import java.io.OutputStream;
|
||||
*
|
||||
* Used to read from a Bluetooth socket.
|
||||
*
|
||||
* TODO: Implement bulk reads (instead of one byte at a time).
|
||||
* @hide
|
||||
*/
|
||||
/*package*/ final class BluetoothOutputStream extends OutputStream {
|
||||
@@ -52,6 +51,37 @@ import java.io.OutputStream;
|
||||
* @since Android 1.0
|
||||
*/
|
||||
public void write(int oneByte) throws IOException {
|
||||
mSocket.writeNative(oneByte);
|
||||
byte b[] = new byte[1];
|
||||
b[0] = (byte)oneByte;
|
||||
mSocket.writeNative(b, 0, 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes {@code count} bytes from the byte array {@code buffer} starting
|
||||
* at position {@code offset} to this stream.
|
||||
*
|
||||
* @param b
|
||||
* the buffer to be written.
|
||||
* @param offset
|
||||
* the start position in {@code buffer} from where to get bytes.
|
||||
* @param count
|
||||
* the number of bytes from {@code buffer} to write to this
|
||||
* stream.
|
||||
* @throws IOException
|
||||
* if an error occurs while writing to this stream.
|
||||
* @throws IndexOutOfBoundsException
|
||||
* if {@code offset < 0} or {@code count < 0}, or if
|
||||
* {@code offset + count} is bigger than the length of
|
||||
* {@code buffer}.
|
||||
* @since Android 1.0
|
||||
*/
|
||||
public void write(byte[] b, int offset, int count) throws IOException {
|
||||
if (b == null) {
|
||||
throw new NullPointerException("buffer is null");
|
||||
}
|
||||
if ((offset | count) < 0 || count > b.length - offset) {
|
||||
throw new IndexOutOfBoundsException("invalid offset or length");
|
||||
}
|
||||
mSocket.writeNative(b, offset, count);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,8 +169,8 @@ public final class BluetoothSocket implements Closeable {
|
||||
/*package*/ native void bindListenNative(int port) throws IOException;
|
||||
/*package*/ native BluetoothSocket acceptNative(int timeout) throws IOException;
|
||||
/*package*/ native int availableNative();
|
||||
/*package*/ native int readNative();
|
||||
/*package*/ native void writeNative(int data);
|
||||
/*package*/ native int readNative(byte[] b, int offset, int length);
|
||||
/*package*/ native int writeNative(byte[] b, int offset, int length);
|
||||
/*package*/ native void closeNative();
|
||||
private native void destroyNative();
|
||||
}
|
||||
|
||||
@@ -227,44 +227,72 @@ static jint availableNative(JNIEnv *env, jobject obj) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static jint readNative(JNIEnv *env, jobject obj) {
|
||||
/** jb must not be null. offset and offset+length must be within array */
|
||||
static jint readNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
|
||||
jint length) {
|
||||
#ifdef HAVE_BLUETOOTH
|
||||
LOGV(__FUNCTION__);
|
||||
|
||||
char buf;
|
||||
int ret;
|
||||
jbyte *b;
|
||||
struct asocket *s = get_socketData(env, obj);
|
||||
|
||||
if (!s)
|
||||
return -1;
|
||||
|
||||
if (asocket_read(s, &buf, 1, -1) < 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
b = env->GetByteArrayElements(jb, NULL);
|
||||
if (b == NULL) {
|
||||
jniThrowIOException(env, EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return (jint)buf;
|
||||
ret = asocket_read(s, &b[offset], length, -1);
|
||||
if (ret < 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->ReleaseByteArrayElements(jb, b, 0);
|
||||
return (jint)ret;
|
||||
|
||||
#endif
|
||||
jniThrowIOException(env, ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void writeNative(JNIEnv *env, jobject obj, jint data) {
|
||||
/** jb must not be null. offset and offset+length must be within array */
|
||||
static jint writeNative(JNIEnv *env, jobject obj, jbyteArray jb, jint offset,
|
||||
jint length) {
|
||||
#ifdef HAVE_BLUETOOTH
|
||||
LOGV(__FUNCTION__);
|
||||
|
||||
const char buf = (char)data;
|
||||
int ret;
|
||||
jbyte *b;
|
||||
struct asocket *s = get_socketData(env, obj);
|
||||
|
||||
if (!s)
|
||||
return;
|
||||
return -1;
|
||||
|
||||
if (asocket_write(s, &buf, 1, -1) < 0)
|
||||
b = env->GetByteArrayElements(jb, NULL);
|
||||
if (b == NULL) {
|
||||
jniThrowIOException(env, EINVAL);
|
||||
return -1;
|
||||
}
|
||||
|
||||
ret = asocket_write(s, &b[offset], length, -1);
|
||||
if (ret < 0) {
|
||||
jniThrowIOException(env, errno);
|
||||
env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
|
||||
return -1;
|
||||
}
|
||||
|
||||
env->ReleaseByteArrayElements(jb, b, JNI_ABORT); // no need to commit
|
||||
return (jint)ret;
|
||||
|
||||
return;
|
||||
#endif
|
||||
jniThrowIOException(env, ENOSYS);
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void closeNative(JNIEnv *env, jobject obj) {
|
||||
@@ -301,8 +329,8 @@ static JNINativeMethod sMethods[] = {
|
||||
{"bindListenNative", "(I)V", (void *) bindListenNative},
|
||||
{"acceptNative", "(I)Landroid/bluetooth/BluetoothSocket;", (void *) acceptNative},
|
||||
{"availableNative", "()I", (void *) availableNative},
|
||||
{"readNative", "()I", (void *) readNative},
|
||||
{"writeNative", "(I)V", (void *) writeNative},
|
||||
{"readNative", "([BII)I", (void *) readNative},
|
||||
{"writeNative", "([BII)I", (void *) writeNative},
|
||||
{"closeNative", "()V", (void *) closeNative},
|
||||
{"destroyNative", "()V", (void *) destroyNative},
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user