Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 47e82dee authored by Nick Pelly's avatar Nick Pelly
Browse files

Implement bulk read and writes for Bluetooth sockets.

Before: 0.1 kB/s
After: 100 kB/s
(in my java BT speed test app)
parent 4599184a
Loading
Loading
Loading
Loading
+39 −3
Original line number Diff line number Diff line
@@ -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);
    }
}
+32 −2
Original line number Diff line number Diff line
@@ -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);
    }
}
+2 −2
Original line number Diff line number Diff line
@@ -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();
}
+39 −11
Original line number Diff line number Diff line
@@ -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) {
    b = env->GetByteArrayElements(jb, NULL);
    if (b == NULL) {
        jniThrowIOException(env, EINVAL);
        return -1;
    }

    ret = asocket_read(s, &b[offset], length, -1);
    if (ret < 0) {
        jniThrowIOException(env, errno);
        env->ReleaseByteArrayElements(jb, b, JNI_ABORT);
        return -1;
    }

    return (jint)buf;
    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},
};