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 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel