From d729352d531a02ee369f109f32fad0f958ed9877 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ji=C5=99=C3=AD=20Pinkava?= <j-pi@seznam.cz>
Date: Tue, 29 Sep 2015 16:47:53 +0200
Subject: [PATCH] librtlsdr: conditional USB transfer resubmit

---
 include/rtl-sdr.h | 15 ++++++++++++++-
 src/librtlsdr.c   | 31 +++++++++++++++++++++++++++----
 src/rtl_adsb.c    |  6 ++++--
 src/rtl_fm.c      |  8 +++++---
 src/rtl_sdr.c     |  6 ++++--
 src/rtl_tcp.c     |  4 +++-
 src/rtl_test.c    |  3 ++-
 7 files changed, 59 insertions(+), 14 deletions(-)

diff --git a/include/rtl-sdr.h b/include/rtl-sdr.h
index fe64bea..f096cd6 100644
--- a/include/rtl-sdr.h
+++ b/include/rtl-sdr.h
@@ -337,7 +337,20 @@ RTLSDR_API int rtlsdr_reset_buffer(rtlsdr_dev_t *dev);
 
 RTLSDR_API int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read);
 
-typedef void(*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx);
+/*!
+ * Send buffer back for use in new asynchronous read.
+ */
+RTLSDR_API void rtlsdr_submit_buffer(rtlsdr_dev_t *dev, unsigned char *buf);
+
+/*!
+ * Callback function for asynchronous reading.
+ *
+ * \return Status indication:
+ *         0 Sucess, buffer can be reused.
+ *         1 Sucess, buffer cannot be reused and shoudl be released by
+ *         calling rtlsdr_submit_buffer(dev, buf) latter.
+ */
+typedef int (*rtlsdr_read_async_cb_t)(unsigned char *buf, uint32_t len, void *ctx);
 
 /*!
  * Read samples from the device asynchronously. This function will block until
diff --git a/src/librtlsdr.c b/src/librtlsdr.c
index cdf1ca9..ec4f3a5 100644
--- a/src/librtlsdr.c
+++ b/src/librtlsdr.c
@@ -1683,6 +1683,21 @@ int rtlsdr_reset_buffer(rtlsdr_dev_t *dev)
 	return 0;
 }
 
+void rtlsdr_submit_buffer(rtlsdr_dev_t *dev, unsigned char *buf)
+{
+	uint32_t i = 0;
+	for ( ; i < dev->xfer_buf_num; ++i) {
+		if (buf == dev->xfer_buf[i])
+			break;
+	}
+	if (i == dev->xfer_buf_num) {
+		fprintf(stderr, "Submitted unknown buffer %p\n", buf);
+		return;
+	}
+
+	libusb_submit_transfer(dev->xfer[i]);
+}
+
 int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read)
 {
 	if (!dev)
@@ -1694,12 +1709,20 @@ int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read)
 static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *xfer)
 {
 	rtlsdr_dev_t *dev = (rtlsdr_dev_t *)xfer->user_data;
+	int r;
 
 	if (LIBUSB_TRANSFER_COMPLETED == xfer->status) {
-		if (dev->cb)
-			dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx);
-
-		libusb_submit_transfer(xfer); /* resubmit transfer */
+		if (dev->cb) {
+			switch (dev->cb(xfer->buffer, xfer->actual_length, dev->cb_ctx)) {
+				default:
+				case 0:
+					libusb_submit_transfer(xfer); /* resubmit transfer */
+					break;
+
+				case 1:
+					break;
+			}
+		}
 		dev->xfer_errors = 0;
 	} else if (LIBUSB_TRANSFER_CANCELLED != xfer->status) {
 #ifndef _WIN32
diff --git a/src/rtl_adsb.c b/src/rtl_adsb.c
index e611e78..afb1fba 100644
--- a/src/rtl_adsb.c
+++ b/src/rtl_adsb.c
@@ -339,12 +339,14 @@ void messages(uint16_t *buf, int len)
 	}
 }
 
-static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
+static int rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
 	if (do_exit) {
-		return;}
+		return 0;}
 	memcpy(buffer, buf, len);
 	safe_cond_signal(&ready, &ready_m);
+
+    return 0;
 }
 
 static void *demod_thread_fn(void *arg)
diff --git a/src/rtl_fm.c b/src/rtl_fm.c
index e89e42d..eb72f1f 100644
--- a/src/rtl_fm.c
+++ b/src/rtl_fm.c
@@ -777,16 +777,16 @@ void full_demod(struct demod_state *d)
 	}
 }
 
-static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
+static int rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
 	int i;
 	struct dongle_state *s = ctx;
 	struct demod_state *d = s->demod_target;
 
 	if (do_exit) {
-		return;}
+		return 0;}
 	if (!ctx) {
-		return;}
+		return 0;}
 	if (s->mute) {
 		for (i=0; i<s->mute; i++) {
 			buf[i] = 127;}
@@ -801,6 +801,8 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 	d->lp_len = len;
 	pthread_rwlock_unlock(&d->rw);
 	safe_cond_signal(&d->ready, &d->ready_m);
+
+	return 0;
 }
 
 static void *dongle_thread_fn(void *arg)
diff --git a/src/rtl_sdr.c b/src/rtl_sdr.c
index e6537ca..81e45ca 100644
--- a/src/rtl_sdr.c
+++ b/src/rtl_sdr.c
@@ -80,11 +80,11 @@ static void sighandler(int signum)
 }
 #endif
 
-static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
+static int rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
 	if (ctx) {
 		if (do_exit)
-			return;
+			return 0;
 
 		if ((bytes_to_read > 0) && (bytes_to_read < len)) {
 			len = bytes_to_read;
@@ -100,6 +100,8 @@ static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 		if (bytes_to_read > 0)
 			bytes_to_read -= len;
 	}
+
+    return 0;
 }
 
 int main(int argc, char **argv)
diff --git a/src/rtl_tcp.c b/src/rtl_tcp.c
index 317e0f3..99e36bd 100644
--- a/src/rtl_tcp.c
+++ b/src/rtl_tcp.c
@@ -141,7 +141,7 @@ static void sighandler(int signum)
 }
 #endif
 
-void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
+int rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
 	if(!do_exit) {
 		struct llist *rpt = (struct llist*)malloc(sizeof(struct llist));
@@ -184,6 +184,8 @@ void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 		pthread_cond_signal(&cond);
 		pthread_mutex_unlock(&ll_mutex);
 	}
+
+    return 0;
 }
 
 static void *tcp_worker(void *arg)
diff --git a/src/rtl_test.c b/src/rtl_test.c
index 9a6cfda..b5276fe 100644
--- a/src/rtl_test.c
+++ b/src/rtl_test.c
@@ -212,13 +212,14 @@ static void ppm_test(uint32_t len)
 }
 #endif
 
-static void rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
+static int rtlsdr_callback(unsigned char *buf, uint32_t len, void *ctx)
 {
 	underrun_test(buf, len, 0);
 #ifndef _WIN32
 	if (test_mode == PPM_BENCHMARK)
 		ppm_test(len);
 #endif
+    return 0;
 }
 
 void e4k_benchmark(void)
-- 
2.6.0

