Browse Source

introduce asynchronous streaming interface

this is an experimental feature
Dimitri Stolnikov 13 years ago
parent
commit
39482fee74
3 changed files with 109 additions and 9 deletions
  1. 6 0
      include/rtl-sdr.h
  2. 13 4
      src/main.c
  3. 90 5
      src/rtl-sdr.c

+ 6 - 0
include/rtl-sdr.h

@@ -61,6 +61,12 @@ 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_async_read_cb_t)(const char *buf, uint32_t len, void *context);
+
+RTLSDR_API int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_async_read_cb_t cb, void *context);
+
+RTLSDR_API int rtlsdr_cancel_async(rtlsdr_dev_t *dev);
+
 #ifdef __cplusplus
 }
 #endif

+ 13 - 4
src/main.c

@@ -24,11 +24,12 @@
 #include <math.h>
 #include <unistd.h>
 
-#include "rtl-sdr.h"
+#include <rtl-sdr.h>
 
 #define READLEN		(16 * 16384)
 
 static int do_exit = 0;
+static rtlsdr_dev_t *dev = NULL;
 
 void usage(void)
 {
@@ -44,6 +45,12 @@ void usage(void)
 static void sighandler(int signum)
 {
 	do_exit = 1;
+	rtlsdr_cancel_async(dev);
+}
+
+void rtlsdr_callback(const char *buf, uint32_t len, void *ctx)
+{
+	fwrite(buf, len, 1, (FILE*)ctx);
 }
 
 int main(int argc, char **argv)
@@ -53,9 +60,8 @@ int main(int argc, char **argv)
 	char *filename = NULL;
 	uint32_t frequency = 0, samp_rate = 2048000;
 	uint8_t buffer[READLEN];
-	uint32_t n_read;
+	int n_read;
 	FILE *file;
-	rtlsdr_dev_t *dev = NULL;
 	uint32_t dev_index = 0, gain = 0;
 
 	while ((opt = getopt(argc, argv, "d:f:g:s:")) != -1) {
@@ -138,6 +144,7 @@ int main(int argc, char **argv)
 		fprintf(stderr, "WARNING: Failed to reset buffers.\n");
 
 	printf("Reading samples...\n");
+#if 0
 	while (!do_exit) {
 		r = rtlsdr_read_sync(dev, buffer, READLEN, &n_read);
 		if (r < 0)
@@ -150,7 +157,9 @@ int main(int argc, char **argv)
 			break;
 		}
 	}
-
+#else
+	rtlsdr_wait_async(dev, rtlsdr_callback, (void *)file);
+#endif
 	if (do_exit)
 		printf("\nUser cancel, exiting...\n");
 

+ 90 - 5
src/rtl-sdr.c

@@ -118,8 +118,16 @@ static rtlsdr_device_t devices[] = {
 	{ 0x0458, 0x707f, "Genius TVGo DVB-T03 USB dongle (Ver. B)" },
 };
 
+#define BUF_COUNT	32
+#define BUF_LENGTH	(16 * 16384)
+
 typedef struct rtlsdr_dev {
 	struct libusb_device_handle *devh;
+	struct libusb_transfer *xfer[BUF_COUNT];
+	unsigned char *xfer_buf[BUF_COUNT];
+	rtlsdr_async_read_cb_t cb;
+	void *context;
+	int run_async;
 	rtlsdr_tuner_t *tuner;
 	int rate; /* Hz */
 } rtlsdr_dev_t;
@@ -698,11 +706,21 @@ err:
 
 int rtlsdr_close(rtlsdr_dev_t *dev)
 {
+	int i;
+
 	if (!dev)
 		return -1;
 
 	libusb_release_interface(dev->devh, 0);
 	libusb_close(dev->devh);
+
+	for(i = 0; i < BUF_COUNT; ++i) {
+		if (dev->xfer[i])
+			libusb_free_transfer(dev->xfer[i]);
+		if (dev->xfer_buf[i])
+			free(dev->xfer_buf[i]);
+	}
+
 	free(dev);
 
 	if (0 == --opened_devices) {
@@ -733,11 +751,78 @@ int rtlsdr_read_sync(rtlsdr_dev_t *dev, void *buf, int len, int *n_read)
 
 	return libusb_bulk_transfer(dev->devh, 0x81, buf, len, n_read, 3000);
 }
-#if 0
-typedef void(*rtlsdr_async_read_cb_t)(const char *buf, uint32_t len, void *ctx);
 
-int rtlsdr_async_loop(rtlsdr_dev_t *dev, rtlsdr_async_read_cb_t cb, void *ctx)
+static void LIBUSB_CALL _libusb_callback(struct libusb_transfer *transfer)
 {
-	return 0;
+	if (LIBUSB_TRANSFER_COMPLETED == transfer->status) {
+		rtlsdr_dev_t *dev = (rtlsdr_dev_t *)transfer->user_data;
+
+		dev->cb(transfer->buffer, transfer->actual_length, dev->context);
+
+		libusb_submit_transfer(transfer); /* resubmit transfer */
+	} else {
+		/*fprintf(stderr, "transfer %d\n", transfer->status);*/
+	}
+}
+
+int rtlsdr_wait_async(rtlsdr_dev_t *dev, rtlsdr_async_read_cb_t cb, void *context)
+{
+	int i, r;
+
+	if (!dev)
+		return -1;
+
+	dev->cb = cb;
+	dev->context = context;
+
+	for(i = 0; i < BUF_COUNT; ++i) {
+		if (dev->xfer[i])
+			continue;
+
+		dev->xfer[i] = libusb_alloc_transfer(0);
+	}
+
+	for(i = 0; i < BUF_COUNT; ++i) {
+		if (dev->xfer_buf[i])
+			continue;
+
+		dev->xfer_buf[i] = (unsigned char *)malloc(BUF_LENGTH);
+	}
+
+	for(i = 0; i < BUF_COUNT; ++i) {
+		libusb_fill_bulk_transfer(dev->xfer[i],
+					  dev->devh,
+					  0x81,
+					  dev->xfer_buf[i], BUF_LENGTH,
+					  _libusb_callback,
+					  (void *)dev, 0);
+
+		libusb_submit_transfer(dev->xfer[i]);
+	}
+
+	dev->run_async = 1;
+
+	while (dev->run_async) {
+		struct timeval tv = { 1, 0 };
+		r = libusb_handle_events_timeout(NULL, &tv);
+		if (r < 0) {
+			/*fprintf(stderr, "handle_events %d\n", r);*/
+			break;
+		}
+	}
+
+	return r;
+}
+
+int rtlsdr_cancel_async(rtlsdr_dev_t *dev)
+{
+	if (!dev)
+		return -1;
+
+	if (dev->run_async) {
+		dev->run_async = 0;
+		return 0;
+	}
+
+	return -2;
 }
-#endif