-
-
Save grag38/a97335c08b68e59e4063 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* 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