Skip to content

Commit 9019cd7

Browse files
committed
Configurable buffer size for input/output streams
1 parent f0778e4 commit 9019cd7

File tree

13 files changed

+91
-49
lines changed

13 files changed

+91
-49
lines changed

java-does-usb/src/main/java/net/codecrete/usb/USBDevice.java

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,23 @@ public interface USBDevice {
292292
* </p>
293293
*
294294
* @param endpointNumber bulk endpoint number (in the range between 1 and 127)
295+
* @param bufferSize approximate buffer size (in bytes)
295296
* @return the new output stream
296297
*/
297-
OutputStream openOutputStream(int endpointNumber);
298+
OutputStream openOutputStream(int endpointNumber, int bufferSize);
299+
300+
/**
301+
* Opens a new output stream to send data to a bulk endpoint.
302+
* <p>
303+
* The buffer is configured with minimal size. In all other aspects, this method
304+
* works like {@link #openOutputStream(int, int)}.
305+
* </p>
306+
* @param endpointNumber bulk endpoint number (in the range between 1 and 127)
307+
* @return the new output stream
308+
*/
309+
default OutputStream openOutputStream(int endpointNumber) {
310+
return openOutputStream(endpointNumber, 1);
311+
}
298312

299313
/**
300314
* Opens a new input stream to receive data from a bulk endpoint.
@@ -309,9 +323,24 @@ public interface USBDevice {
309323
* </p>
310324
*
311325
* @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit)
326+
* @param bufferSize approximate buffer size (in bytes)
327+
* @return the new input stream
328+
*/
329+
InputStream openInputStream(int endpointNumber, int bufferSize);
330+
331+
/**
332+
* Opens a new input stream to receive data from a bulk endpoint.
333+
* <p>
334+
* The buffer is configured with minimal size. In all other aspects, this method
335+
* works like {@link #openInputStream(int, int)}.
336+
* </p>
337+
*
338+
* @param endpointNumber bulk endpoint number (in the range between 1 and 127, i.e. without the direction bit)
312339
* @return the new input stream
313340
*/
314-
InputStream openInputStream(int endpointNumber);
341+
default InputStream openInputStream(int endpointNumber) {
342+
return openInputStream(endpointNumber, 1);
343+
}
315344

316345
/**
317346
* Aborts all transfers on an endpoint.

java-does-usb/src/main/java/net/codecrete/usb/common/EndpointInputStream.java

Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -35,14 +35,12 @@
3535
*/
3636
public abstract class EndpointInputStream extends InputStream {
3737

38-
private static final int MAX_OUTSTANDING_TRANSFERS = 8;
39-
4038
protected USBDeviceImpl device;
4139
protected final int endpointNumber;
4240
// Arena to allocate buffers and completion handlers
4341
protected final Arena arena;
44-
// Size of buffers (multiple of packet size)
45-
protected final int bufferSize;
42+
// Transfer size (multiple of packet size)
43+
protected final int transferSize;
4644
// Queue of completed transfers
4745
private final ArrayBlockingQueue<Transfer> completedTransferQueue;
4846
// Number of outstanding transfers (includes transfers pending with the
@@ -58,23 +56,29 @@ public abstract class EndpointInputStream extends InputStream {
5856
*
5957
* @param device USB device
6058
* @param endpointNumber endpoint number
59+
* @param bufferSize approximate buffer size (in bytes)
6160
*/
62-
protected EndpointInputStream(USBDeviceImpl device, int endpointNumber) {
61+
protected EndpointInputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) {
6362
this.device = device;
6463
this.endpointNumber = endpointNumber;
6564
arena = Arena.openShared();
66-
bufferSize = 4 * device.getEndpoint(USBDirection.IN, endpointNumber).packetSize();
65+
66+
int packetSize = device.getEndpoint(USBDirection.IN, endpointNumber).packetSize();
67+
int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize));
68+
n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS)
69+
transferSize = n * packetSize;
70+
int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2);
6771

6872
configureEndpoint();
6973

70-
completedTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS);
74+
completedTransferQueue = new ArrayBlockingQueue<>(maxOutstandingTransfers);
7175

7276
// create all transfers, and submit them except one
7377
try {
74-
for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) {
78+
for (int i = 0; i < maxOutstandingTransfers; i++) {
7579
final var transfer = device.createTransfer();
76-
transfer.data = arena.allocate(bufferSize, 8);
77-
transfer.dataSize = bufferSize;
80+
transfer.data = arena.allocate(transferSize, 8);
81+
transfer.dataSize = transferSize;
7882
transfer.completion = this::onCompletion;
7983

8084
if (i == 0) {

java-does-usb/src/main/java/net/codecrete/usb/common/EndpointOutputStream.java

Lines changed: 16 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,14 @@
3737
*/
3838
public abstract class EndpointOutputStream extends OutputStream {
3939

40-
private static final int MAX_OUTSTANDING_TRANSFERS = 4;
4140

4241
protected USBDeviceImpl device;
4342
protected final int endpointNumber;
4443
protected final Arena arena;
4544
// Endpoint's packet size
4645
private final int packetSize;
47-
// Size of buffers (multiple of packet size)
48-
private final int bufferSize;
46+
// Transfer size (multiple of packet size)
47+
private final int transferSize;
4948
// Blocking queue of available transfers (to limit the number of submitted transfers)
5049
private final ArrayBlockingQueue<Transfer> availableTransferQueue;
5150
private boolean needsZlp;
@@ -60,22 +59,27 @@ public abstract class EndpointOutputStream extends OutputStream {
6059
*
6160
* @param device USB device
6261
* @param endpointNumber endpoint number
62+
* @param bufferSize approximate buffer size (in bytes)
6363
*/
64-
protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber) {
64+
protected EndpointOutputStream(USBDeviceImpl device, int endpointNumber, int bufferSize) {
6565
this.device = device;
6666
this.endpointNumber = endpointNumber;
67-
packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize();
68-
bufferSize = packetSize;
6967
arena = Arena.openShared();
7068

69+
packetSize = device.getEndpoint(USBDirection.OUT, endpointNumber).packetSize();
70+
int n = (int) Math.round(Math.sqrt((double) bufferSize / packetSize));
71+
n = Math.min(Math.max(n, 4), 32); // 32 limits packet size to 16KB (for USB HS)
72+
transferSize = n * packetSize;
73+
int maxOutstandingTransfers = Math.max((bufferSize + transferSize / 2) / transferSize, 2);
74+
7175
configureEndpoint();
7276

73-
availableTransferQueue = new ArrayBlockingQueue<>(MAX_OUTSTANDING_TRANSFERS);
77+
availableTransferQueue = new ArrayBlockingQueue<>(maxOutstandingTransfers);
7478

7579
// prefill transfer queue
76-
for (int i = 0; i < MAX_OUTSTANDING_TRANSFERS; i++) {
80+
for (int i = 0; i < maxOutstandingTransfers; i++) {
7781
final var transfer = device.createTransfer();
78-
transfer.data = arena.allocate(bufferSize, 8);
82+
transfer.data = arena.allocate(transferSize, 8);
7983
transfer.completion = this::onCompletion;
8084

8185
if (i == 0) {
@@ -113,7 +117,7 @@ public void write(int b) throws IOException {
113117

114118
currentTransfer.data.set(JAVA_BYTE, writeOffset, (byte) b);
115119
writeOffset += 1;
116-
if (writeOffset == bufferSize)
120+
if (writeOffset == transferSize)
117121
submitTransfer(writeOffset);
118122
}
119123

@@ -123,13 +127,13 @@ public void write(byte[] b, int off, int len) throws IOException {
123127
throw new IOException("Bulk endpoint output stream has been closed");
124128

125129
while (len > 0) {
126-
int chunkSize = Math.min(len, bufferSize - writeOffset);
130+
int chunkSize = Math.min(len, transferSize - writeOffset);
127131
MemorySegment.copy(b, off, currentTransfer.data, JAVA_BYTE, writeOffset, chunkSize);
128132
writeOffset += chunkSize;
129133
off += chunkSize;
130134
len -= chunkSize;
131135

132-
if (writeOffset == bufferSize)
136+
if (writeOffset == transferSize)
133137
submitTransfer(writeOffset);
134138
}
135139
}

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointInputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
public class LinuxEndpointInputStream extends EndpointInputStream {
1515

16-
LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber) {
17-
super(device, endpointNumber);
16+
LinuxEndpointInputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) {
17+
super(device, endpointNumber, bufferSize);
1818
}
1919

2020
@Override

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxEndpointOutputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
public class LinuxEndpointOutputStream extends EndpointOutputStream {
1515

16-
LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber) {
17-
super(device, endpointNumber);
16+
LinuxEndpointOutputStream(LinuxUSBDevice device, int endpointNumber, int bufferSize) {
17+
super(device, endpointNumber, bufferSize);
1818
}
1919

2020
@Override

java-does-usb/src/main/java/net/codecrete/usb/linux/LinuxUSBDevice.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -304,18 +304,18 @@ public synchronized void abortTransfers(USBDirection direction, int endpointNumb
304304
}
305305

306306
@Override
307-
public InputStream openInputStream(int endpointNumber) {
307+
public InputStream openInputStream(int endpointNumber, int bufferSize) {
308308
// check that endpoint number is valid
309309
getEndpoint(USBDirection.IN, endpointNumber, USBTransferType.BULK, null);
310310

311-
return new LinuxEndpointInputStream(this, endpointNumber);
311+
return new LinuxEndpointInputStream(this, endpointNumber, bufferSize);
312312
}
313313

314314
@Override
315-
public OutputStream openOutputStream(int endpointNumber) {
315+
public OutputStream openOutputStream(int endpointNumber, int bufferSize) {
316316
// check that endpoint number is valid
317317
getEndpoint(USBDirection.OUT, endpointNumber, USBTransferType.BULK, null);
318318

319-
return new LinuxEndpointOutputStream(this, endpointNumber);
319+
return new LinuxEndpointOutputStream(this, endpointNumber, bufferSize);
320320
}
321321
}

java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointInputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
public class MacosEndpointInputStream extends EndpointInputStream {
1414

15-
MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber) {
16-
super(device, endpointNumber);
15+
MacosEndpointInputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) {
16+
super(device, endpointNumber, bufferSize);
1717
}
1818

1919
@Override

java-does-usb/src/main/java/net/codecrete/usb/macos/MacosEndpointOutputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@
1212

1313
public class MacosEndpointOutputStream extends EndpointOutputStream {
1414

15-
MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber) {
16-
super(device, endpointNumber);
15+
MacosEndpointOutputStream(MacosUSBDevice device, int endpointNumber, int bufferSize) {
16+
super(device, endpointNumber, bufferSize);
1717
}
1818

1919
@Override

java-does-usb/src/main/java/net/codecrete/usb/macos/MacosUSBDevice.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -541,19 +541,19 @@ public void clearHalt(USBDirection direction, int endpointNumber) {
541541
}
542542

543543
@Override
544-
public InputStream openInputStream(int endpointNumber) {
544+
public InputStream openInputStream(int endpointNumber, int bufferSize) {
545545
// check that endpoint number is valid
546546
getEndpointInfo(endpointNumber, USBDirection.IN, USBTransferType.BULK, null);
547547

548-
return new MacosEndpointInputStream(this, endpointNumber);
548+
return new MacosEndpointInputStream(this, endpointNumber, bufferSize);
549549
}
550550

551551
@Override
552-
public OutputStream openOutputStream(int endpointNumber) {
552+
public OutputStream openOutputStream(int endpointNumber, int bufferSize) {
553553
// check that endpoint number is valid
554554
getEndpointInfo(endpointNumber, USBDirection.OUT, USBTransferType.BULK, null);
555555

556-
return new MacosEndpointOutputStream(this, endpointNumber);
556+
return new MacosEndpointOutputStream(this, endpointNumber, bufferSize);
557557
}
558558

559559
@Override

java-does-usb/src/main/java/net/codecrete/usb/windows/WindowsEndpointInputStream.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@
1313

1414
public class WindowsEndpointInputStream extends EndpointInputStream {
1515

16-
WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber) {
17-
super(device, endpointNumber);
16+
WindowsEndpointInputStream(WindowsUSBDevice device, int endpointNumber, int bufferSize) {
17+
super(device, endpointNumber, bufferSize);
1818
}
1919

2020
@Override

0 commit comments

Comments
 (0)