Skip to content

Instantly share code, notes, and snippets.

@grag38
Forked from asquared/96i.cpp
Created June 29, 2014 15:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grag38/a97335c08b68e59e4063 to your computer and use it in GitHub Desktop.
Save grag38/a97335c08b68e59e4063 to your computer and use it in GitHub Desktop.
/*
* Copyright 2013 Exavideo LLC.
*
* This is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <libusb.h>
const uint16_t vid_mixer = 0x0499;
const uint16_t pid_mixer = 0x5500;
void print_config_descriptor(const libusb_config_descriptor *confd);
int flag;
void main_loop(libusb_device_handle *);
void print_iso_packets(libusb_transfer *);
void write_iso_packets(libusb_transfer *);
int read_iso_packets(libusb_transfer *);
int main( ) {
int err;
flag = 0;
libusb_device_handle *mixer_handle;
libusb_device *mixer_dev;
libusb_config_descriptor *confd;
libusb_init(NULL);
mixer_handle = libusb_open_device_with_vid_pid(
NULL, vid_mixer, pid_mixer
);
if (mixer_handle == NULL) {
fprintf(stderr, "could not find device or error opening\n");
goto failed_to_open_device;
}
mixer_dev = libusb_get_device(mixer_handle);
/* if nothing else, this resets the other end */
err = libusb_set_configuration(mixer_handle, 1);
if (err != 0) {
fprintf(stderr, "could not get configuration 1\n");
goto failed_with_device_open;
}
/* try to read descriptor */
err = libusb_get_active_config_descriptor(mixer_dev, &confd);
if (err != 0) {
fprintf(stderr, "could not get config 1 descriptor\n");
goto failed_with_device_open;
}
print_config_descriptor(confd);
libusb_free_config_descriptor(confd);
/* try to claim interface 1 (audio capture) */
err = libusb_claim_interface(mixer_handle, 1);
if (err != 0) {
fprintf(stderr, "could not claim interface 1\n");
goto failed_with_device_open;
}
/* and set it to alt setting 1 (48kHz?) */
err = libusb_set_interface_alt_setting(mixer_handle, 1, 1);
if (err != 0) {
fprintf(stderr, "failed to set interface 1 to alternate setting 1\n");
goto failed_with_interface_claimed;
}
/* do same for interface 2 (audio capture) */
err = libusb_claim_interface(mixer_handle, 2);
if (err != 0) {
fprintf(stderr, "could not claim interface 2\n");
goto failed_with_interface_claimed;
}
err = libusb_set_interface_alt_setting(mixer_handle, 2, 1);
if (err != 0) {
fprintf(stderr, "failed to set interface 2 to alternate setting 1\n");
goto failed_with_interface_claimed;
}
/* start reading audio data? */
main_loop(mixer_handle);
failed_with_interface_claimed:
libusb_release_interface(mixer_handle, 1);
libusb_release_interface(mixer_handle, 2);
failed_with_device_open:
libusb_close(mixer_handle);
failed_to_open_device:
libusb_exit(NULL);
}
void print_endpoint_descriptor(const libusb_endpoint_descriptor *epd) {
fprintf(stderr, "\t\t\tbLength=%d\n", epd->bLength);
fprintf(stderr, "\t\t\tbDescriptorType=%d\n", epd->bDescriptorType);
fprintf(stderr, "\t\t\tbEndpointAddress=0x%x\n", epd->bEndpointAddress);
fprintf(stderr, "\t\t\tbmAttributes=0x%x\n", epd->bmAttributes);
fprintf(stderr, "\t\t\twMaxPacketSize=%d\n", epd->wMaxPacketSize);
fprintf(stderr, "\t\t\tbInterval=%d\n", epd->bInterval);
fprintf(stderr, "\t\t\tbRefresh=%d\n", epd->bRefresh);
fprintf(stderr, "\t\t\tbSynchAddress=%d\n", epd->bSynchAddress);
}
void print_interface_descriptor(const libusb_interface_descriptor *ifd) {
uint8_t i;
fprintf(stderr, "\t\tbLength=%d\n", ifd->bLength);
fprintf(stderr, "\t\tbDescriptorType=%d\n", ifd->bDescriptorType);
fprintf(stderr, "\t\tbInterfaceNumber=%d\n", ifd->bInterfaceNumber);
fprintf(stderr, "\t\tbAlternateSetting=%d\n", ifd->bAlternateSetting);
fprintf(stderr, "\t\tbNumEndpoints=%d\n", ifd->bNumEndpoints);
fprintf(stderr, "\t\tbInterfaceClass=%d\n", ifd->bInterfaceClass);
fprintf(stderr, "\t\tbInterfaceProtocol=%d\n", ifd->bInterfaceProtocol);
for (i = 0; i < ifd->bNumEndpoints; i++) {
fprintf(stderr, "\t\tendpoint %d:\n", i);
print_endpoint_descriptor(&ifd->endpoint[i]);
}
}
void print_interface_data(const libusb_interface *iface) {
int i;
for (i = 0; i < iface->num_altsetting; i++) {
fprintf(stderr, "\talternate setting %d:\n", i);
print_interface_descriptor(&iface->altsetting[i]);
}
}
void print_config_descriptor(const libusb_config_descriptor *confd) {
uint8_t i;
fprintf(stderr, "bLength=%d\n", confd->bLength);
fprintf(stderr, "bDescriptorType=%d\n", confd->bDescriptorType);
fprintf(stderr, "wTotalLength=%d\n", confd->wTotalLength);
fprintf(stderr, "bNumInterfaces=%d\n", confd->bNumInterfaces);
fprintf(stderr, "bConfigurationValue=%d\n", confd->bConfigurationValue);
fprintf(stderr, "iConfiguration=%d\n", confd->iConfiguration);
fprintf(stderr, "bmAttributes=0x%x\n", confd->bmAttributes);
fprintf(stderr, "MaxPower=%d\n", confd->MaxPower);
for (i = 0; i < confd->bNumInterfaces; i++) {
fprintf(stderr, "interface %d:\n", i);
print_interface_data(&confd->interface[i]);
}
}
void in_cb(struct libusb_transfer *isoxfer) {
switch (isoxfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
write_iso_packets(isoxfer);
break;
default:
break;
}
/* resubmit the transfer? */
libusb_submit_transfer(isoxfer);
}
void out_cb(struct libusb_transfer *isoxfer) {
switch (isoxfer->status) {
case LIBUSB_TRANSFER_COMPLETED:
if (read_iso_packets(isoxfer) == 0) {
flag = 1;
}
break;
default:
break;
}
/* resubmit the transfer? */
libusb_submit_transfer(isoxfer);
}
libusb_transfer *alloc_iso_xfer(
libusb_device_handle *handle,
unsigned char endpt,
libusb_transfer_cb_fn cb,
int pktsz = -1
) {
struct libusb_transfer *isoxfer;
struct libusb_device *dev;
const int num_iso_packets = 256;
unsigned char *buf;
size_t bufsize;
int max_packet_size;
dev = libusb_get_device(handle);
max_packet_size = libusb_get_max_iso_packet_size(dev, endpt);
if (
max_packet_size == LIBUSB_ERROR_NOT_FOUND
|| max_packet_size == LIBUSB_ERROR_OTHER
) {
fprintf(stderr, "could not get max packet size for endpoint\n");
return NULL;
}
if (pktsz == -1) {
pktsz = max_packet_size;
}
if (pktsz > max_packet_size) {
fprintf(stderr, "invalid packet size\n");
return NULL;
}
bufsize = num_iso_packets * pktsz;
buf = new unsigned char[bufsize];
isoxfer = libusb_alloc_transfer(num_iso_packets);
if (isoxfer == NULL) {
fprintf(stderr, "failed to allocate isochronous transfer\n");
return NULL;
}
libusb_fill_iso_transfer(
isoxfer, handle, endpt,
buf, bufsize, num_iso_packets,
cb, NULL, 10000
);
libusb_set_iso_packet_lengths(isoxfer, pktsz);
return isoxfer;
}
void main_loop(libusb_device_handle *mixer_handle) {
const int num_transfers = 16;
libusb_transfer *xfer;
int i, err;
/* start incoming transfers */
for (i = 0; i < num_transfers; i++) {
xfer = alloc_iso_xfer(mixer_handle, 0x86, in_cb);
if (xfer == NULL) {
fprintf(stderr, "failed to allocate transfer\n");
continue;
}
err = libusb_submit_transfer(xfer);
if (err != 0) {
fprintf(stderr, "failed to submit transfer\n");
}
}
/* and outgoing transfers */
for (i = 0; i < num_transfers; i++) {
xfer = alloc_iso_xfer(mixer_handle, 0x07, out_cb, 288);
if (xfer == NULL) {
fprintf(stderr, "failed to allocate transfer\n");
continue;
}
read_iso_packets(xfer);
err = libusb_submit_transfer(xfer);
if (err != 0) {
fprintf(stderr, "failed to submit transfer\n");
}
}
/* let the callback do the rest of the work */
while (flag == 0) {
libusb_handle_events(NULL);
}
}
const char *transfer_status_string(libusb_transfer_status s) {
switch (s) {
case LIBUSB_TRANSFER_COMPLETED:
return "SUCCESS";
case LIBUSB_TRANSFER_ERROR:
return "ERROR";
case LIBUSB_TRANSFER_TIMED_OUT:
return "TIMEOUT";
case LIBUSB_TRANSFER_CANCELLED:
return "CANCELED";
case LIBUSB_TRANSFER_STALL:
return "STALL";
case LIBUSB_TRANSFER_NO_DEVICE:
return "DISCONNECT";
case LIBUSB_TRANSFER_OVERFLOW:
return "OVERFLOW";
default:
return "UNKNOWN";
}
}
void print_iso_packets(libusb_transfer *xfer) {
int i;
libusb_iso_packet_descriptor *isopkt;
for (i = 0; i < xfer->num_iso_packets; i++) {
isopkt = &(xfer->iso_packet_desc[i]);
fprintf(stderr, "packet %d length=%u actual_length=%u [%10s]\n",
i, isopkt->length, isopkt->actual_length,
transfer_status_string(isopkt->status)
);
}
}
void write_iso_packets(libusb_transfer *xfer) {
int i;
unsigned char *data;
size_t len;
/* write isochronous data to stdout */
for (i = 0; i < xfer->num_iso_packets; i++) {
data = libusb_get_iso_packet_buffer_simple(xfer, i);
len = xfer->iso_packet_desc[i].actual_length;
fwrite(data, len, 1, stdout);
}
}
int read_iso_packets(libusb_transfer *xfer) {
int i;
unsigned char *data;
size_t len;
/* write isochronous data to stdout */
for (i = 0; i < xfer->num_iso_packets; i++) {
data = libusb_get_iso_packet_buffer_simple(xfer, i);
len = xfer->iso_packet_desc[i].actual_length;
if (fread(data, len, 1, stdin) == 0) {
return 0;
}
}
return 1;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment