[Spice-devel] [usbredir PATCH v5 1/2] usbredirhost: new callback for iso streams
Victor Toso
victortoso at redhat.com
Thu Oct 22 07:07:18 PDT 2015
For streaming devices it might be necessary from application to drop
data for different reasons. This patch provides a new callback that it
is called before queueing the most recent iso packages.
Related: https://bugzilla.redhat.com/show_bug.cgi?id=1264156
---
usbredirhost/usbredirhost.c | 63 +++++++++++++++++++++++++++++++++++++++++++--
usbredirhost/usbredirhost.h | 12 +++++++++
2 files changed, 73 insertions(+), 2 deletions(-)
diff --git a/usbredirhost/usbredirhost.c b/usbredirhost/usbredirhost.c
index ad30722..4c20bff 100644
--- a/usbredirhost/usbredirhost.c
+++ b/usbredirhost/usbredirhost.c
@@ -23,6 +23,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
+#include <stdbool.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
@@ -109,6 +110,7 @@ struct usbredirhost {
usbredirparser_read read_func;
usbredirparser_write write_func;
usbredirhost_flush_writes flush_writes_func;
+ usbredirhost_can_write_iso can_write_iso_func;
void *func_priv;
int verbose;
libusb_context *ctx;
@@ -130,6 +132,11 @@ struct usbredirhost {
struct usbredirtransfer transfers_head;
struct usbredirfilter_rule *filter_rules;
int filter_rules_count;
+ struct {
+ uint64_t higher;
+ uint64_t lower;
+ bool dropping;
+ } iso_threshold;
};
struct usbredirhost_dev_ids {
@@ -1003,6 +1010,31 @@ static void usbredirhost_send_stream_status(struct usbredirhost *host,
}
}
+static int usbredirhost_can_write_iso_package(struct usbredirhost *host,
+ uint8_t ep)
+{
+ uint64_t size;
+
+ if (!host->can_write_iso_func)
+ return true;
+
+ size = host->can_write_iso_func(host->func_priv);
+ if (size >= host->iso_threshold.higher) {
+ if (!host->iso_threshold.dropping)
+ DEBUG("START dropping isoc packets %lu buffer > %lu hi threshold",
+ size, host->iso_threshold.higher);
+ host->iso_threshold.dropping = true;
+ } else if (size < host->iso_threshold.lower) {
+ if (host->iso_threshold.dropping)
+ DEBUG("STOP dropping isoc packets %lu buffer < %lu low threshold",
+ size, host->iso_threshold.lower);
+
+ host->iso_threshold.dropping = false;
+ }
+
+ return !host->iso_threshold.dropping;
+}
+
static void usbredirhost_send_stream_data(struct usbredirhost *host,
uint64_t id, uint8_t ep, uint8_t status, uint8_t *data, int len)
{
@@ -1028,8 +1060,10 @@ static void usbredirhost_send_stream_data(struct usbredirhost *host,
.status = status,
.length = len,
};
- usbredirparser_send_iso_packet(host->parser, id, &iso_packet,
- data, len);
+
+ if (usbredirhost_can_write_iso_package(host, ep))
+ usbredirparser_send_iso_packet(host->parser, id, &iso_packet,
+ data, len);
break;
}
case usb_redir_type_bulk: {
@@ -1120,6 +1154,16 @@ static void usbredirhost_stop_stream(struct usbredirhost *host,
FLUSH(host);
}
+static void usbredirhost_set_iso_threshold(struct usbredirhost *host,
+ uint8_t pkts_per_transfer, uint8_t transfer_count, uint16_t max_packetsize)
+{
+ uint64_t reference = pkts_per_transfer * transfer_count * max_packetsize;
+ host->iso_threshold.lower = reference / 2;
+ host->iso_threshold.higher = reference * 2;
+ DEBUG("higher threshold is %lu bytes | lower threshold is %lu bytes",
+ host->iso_threshold.higher, host->iso_threshold.lower);
+}
+
/* Called from both parser read and packet complete callbacks */
static void usbredirhost_alloc_stream_unlocked(struct usbredirhost *host,
uint64_t id, uint8_t ep, uint8_t type, uint8_t pkts_per_transfer,
@@ -1178,6 +1222,10 @@ static void usbredirhost_alloc_stream_unlocked(struct usbredirhost *host,
host->endpoint[EP2I(ep)].transfer[i], ISO_TIMEOUT);
libusb_set_iso_packet_lengths(
host->endpoint[EP2I(ep)].transfer[i]->transfer, pkt_size);
+
+ usbredirhost_set_iso_threshold(
+ host, pkts_per_transfer, transfer_count,
+ host->endpoint[EP2I(ep)].max_packetsize);
break;
case usb_redir_type_bulk:
libusb_fill_bulk_transfer(
@@ -1358,6 +1406,17 @@ static void usbredirhost_log_data(struct usbredirhost *host, const char *desc,
/**************************************************************************/
+void usbredirhost_set_cb_can_write_iso(struct usbredirhost *host,
+ usbredirhost_can_write_iso can_write_iso_func)
+{
+ if (!host) {
+ ERROR("invalid usbredirhost");
+ return;
+ }
+
+ host->can_write_iso_func = can_write_iso_func;
+}
+
/* Return value:
0 All ok
1 Packet borked, continue with next packet / urb
diff --git a/usbredirhost/usbredirhost.h b/usbredirhost/usbredirhost.h
index c0042c9..a03b10b 100644
--- a/usbredirhost/usbredirhost.h
+++ b/usbredirhost/usbredirhost.h
@@ -33,6 +33,8 @@ struct usbredirhost;
typedef void (*usbredirhost_flush_writes)(void *priv);
+typedef uint64_t (*usbredirhost_can_write_iso)(void *priv);
+
/* This function creates an usbredirhost instance, including its embedded
libusbredirparser instance and sends the initial usb_redir_hello packet to
the usb-guest.
@@ -114,6 +116,16 @@ void usbredirhost_close(struct usbredirhost *host);
int usbredirhost_set_device(struct usbredirhost *host,
libusb_device_handle *usb_dev_handle);
+/* Call this function to set a callback in usbredirhost.
+ The usbredirhost_can_write_iso callback should return the application's
+ buffer size (in bytes) that are handling the isochronous data.
+ usbredirhost set two levels of threshold based in the information provided
+ by the device; if buffer size is higher then the higher threshold, usbredir
+ will drop isochronous packages till it reaches lower threshold.
+*/
+void usbredirhost_set_cb_can_write_iso(struct usbredirhost *host,
+ usbredirhost_can_write_iso can_write_iso_func);
+
/* Call this whenever there is data ready for the usbredirhost to read from
the usb-guest
returns 0 on success, or an error code from the below enum on error.
--
2.5.0
More information about the Spice-devel
mailing list