ref: 1fb43347e61f11fe9e8b079409f727c1f3450fbd
parent: f80e89b8eccdea0815e9f93be667c5aa95d01db8
author: Maido Käära <maido@producement.com>
date: Mon Dec 12 10:58:59 EST 2022
Add audio support
--- /dev/null
+++ b/audio.c
@@ -1,0 +1,158 @@
+#include <libusb.h>
+#include <errno.h>
+#include <android/log.h>
+#include <jni.h>
+#include <SDL_audio.h>
+#include <SDL_log.h>
+#include "audio.h"
+
+#define EP_ISO_IN 0x85
+#define IFACE_NUM 4
+
+#define NUM_TRANSFERS 10
+#define PACKET_SIZE 180
+#define NUM_PACKETS 10
+
+static unsigned long num_bytes = 0, num_xfer = 0;
+static struct timeval tv_start;
+
+static int do_exit = 1;
+
+static void cb_xfr(struct libusb_transfer *xfr) {+ unsigned int i;
+
+ int len = 0;
+
+ for (i = 0; i < xfr->num_iso_packets; i++) {+ struct libusb_iso_packet_descriptor *pack = &xfr->iso_packet_desc[i];
+
+ if (pack->status != LIBUSB_TRANSFER_COMPLETED) {+ SDL_Log("Error (status %d: %s) :", pack->status,+ libusb_error_name(pack->status));
+ /* This doesn't happen, so bail out if it does. */
+ exit(EXIT_FAILURE);
+ }
+
+ const uint8_t *data = libusb_get_iso_packet_buffer_simple(xfr, i);
+
+ SDL_QueueAudio(1, data, pack->actual_length);
+
+ len += pack->length;
+ }
+
+ num_bytes += len;
+ num_xfer++;
+
+ if (libusb_submit_transfer(xfr) < 0) {+ SDL_Log("error re-submitting URB\n");+ exit(1);
+ }
+
+}
+
+static int benchmark_in(libusb_device_handle *devh, uint8_t ep) {+ static uint8_t buf[PACKET_SIZE * NUM_PACKETS];
+ static struct libusb_transfer *xfr[NUM_TRANSFERS];
+ int num_iso_pack = NUM_PACKETS;
+ int i;
+
+ /* NOTE: To reach maximum possible performance the program must
+ * submit *multiple* transfers here, not just one.
+ *
+ * When only one transfer is submitted there is a gap in the bus
+ * schedule from when the transfer completes until a new transfer
+ * is submitted by the callback. This causes some jitter for
+ * isochronous transfers and loss of throughput for bulk transfers.
+ *
+ * This is avoided by queueing multiple transfers in advance, so
+ * that the host controller is always kept busy, and will schedule
+ * more transfers on the bus while the callback is running for
+ * transfers which have completed on the bus.
+ */
+ for (i = 0; i < NUM_TRANSFERS; i++) {+ xfr[i] = libusb_alloc_transfer(num_iso_pack);
+ if (!xfr[i]) {+ SDL_Log("Could not allocate transfer");+ return -ENOMEM;
+ }
+
+ libusb_fill_iso_transfer(xfr[i], devh, ep, buf,
+ sizeof(buf), num_iso_pack, cb_xfr, NULL, 1000);
+ libusb_set_iso_packet_lengths(xfr[i], sizeof(buf) / num_iso_pack);
+
+ libusb_submit_transfer(xfr[i]);
+ }
+
+ gettimeofday(&tv_start, NULL);
+
+ return 1;
+}
+
+int audio_setup(libusb_device_handle *devh) {+ SDL_Log("UsbAudio setup");+
+ int rc;
+
+ rc = libusb_kernel_driver_active(devh, IFACE_NUM);
+ if (rc == 1) {+ SDL_Log("Detaching kernel driver");+ rc = libusb_detach_kernel_driver(devh, IFACE_NUM);
+ if (rc < 0) {+ SDL_Log("Could not detach kernel driver: %s\n",+ libusb_error_name(rc));
+ libusb_close(devh);
+ libusb_exit(NULL);
+ return rc;
+ }
+ }
+
+ rc = libusb_claim_interface(devh, IFACE_NUM);
+ if (rc < 0) {+ SDL_Log("Error claiming interface: %s\n", libusb_error_name(rc));+ libusb_close(devh);
+ libusb_exit(NULL);
+ return rc;
+ }
+
+ rc = libusb_set_interface_alt_setting(devh, IFACE_NUM, 1);
+ if (rc < 0) {+ SDL_Log("Error setting alt setting: %s\n", libusb_error_name(rc));+ libusb_close(devh);
+ libusb_exit(NULL);
+ return rc;
+ }
+
+
+// Good to go
+ do_exit = 0;
+ SDL_Log("Starting capture");+ if ((rc = benchmark_in(devh, EP_ISO_IN)) < 0) {+ SDL_Log("Capture failed to start: %d", rc);+ return rc;
+ }
+
+ static SDL_AudioSpec audio_spec;
+ audio_spec.format = AUDIO_S16;
+ audio_spec.channels = 2;
+ audio_spec.freq = 44100;
+
+ if (SDL_OpenAudio(&audio_spec, NULL) < 0) {+ SDL_Log("Couldn't open audio: %s\n", SDL_GetError());+ exit(-1);
+ }
+
+ SDL_PauseAudio(0);
+
+ SDL_Log("Successful init");+ return 1;
+}
+
+JNIEXPORT void JNICALL
+Java_io_maido_m8client_M8SDLActivity_loop(JNIEnv *env, jobject thiz) {+ while (!do_exit) {+ int rc = libusb_handle_events(NULL);
+ if (rc != LIBUSB_SUCCESS) {+ break;
+ }
+ }
+}
--- /dev/null
+++ b/audio.h
@@ -1,0 +1,6 @@
+#ifndef _AUDIO_H_
+#define _AUDIO_H_
+
+int audio_setup(libusb_device_handle *devh);
+
+#endif
--- a/serial.c
+++ b/serial.c
@@ -16,7 +16,10 @@
#ifdef USE_LIBUSB
#include <libusb.h>
+#include "audio.h"
+#define UNUSED __attribute__((unused))
+
static int ep_out_addr = 0x03;
static int ep_in_addr = 0x83;
@@ -149,7 +152,7 @@
return 0;
}
- return 1;
+ return audio_setup(devh);
}
int reset_display() {@@ -235,6 +238,7 @@
return 1;
}
+
#else
#include <libserialport.h>
@@ -481,4 +485,5 @@
return 1;
}
#endif
+
--
⑨