Browse Source

Add volume/mute feature to AudioInputUSB

Change descriptor and code to handle features for USB Audio
main
Fernando Trias 8 years ago
parent
commit
3a9025dd06
4 changed files with 141 additions and 5 deletions
  1. +66
    -0
      teensy3/usb_audio.cpp
  2. +43
    -0
      teensy3/usb_audio.h
  3. +13
    -2
      teensy3/usb_desc.c
  4. +19
    -3
      teensy3/usb_dev.c

+ 66
- 0
teensy3/usb_audio.cpp View File

@@ -44,6 +44,8 @@ audio_block_t * AudioInputUSB::ready_right;
uint16_t AudioInputUSB::incoming_count;
uint8_t AudioInputUSB::receive_flag;

struct usb_audio_features_struct AudioInputUSB::features = {0,0,FEATURE_MAX_VOLUME};

#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4)))
uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR;
uint32_t usb_audio_sync_feedback DMABUFATTR;
@@ -342,6 +344,70 @@ unsigned int usb_audio_transmit_callback(void)
return target * 4;
}

int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen)
{
struct setup_struct setup = *((struct setup_struct *)stp);
if (setup.bmRequestType==0xA1) { // should check bRequest too, and UnitID
if (setup.bChannel==0) { // only support main, but in theory could do left/right as well
if (setup.bCS==0x01) { // mute
data[0] = AudioInputUSB::features.mute; // 1=mute, 0=unmute
*datalen = 1;
return 1;
}
else if (setup.bCS==0x02) { // volume
if (setup.bRequest==0x81) { // GET_CURR
data[0] = AudioInputUSB::features.volume & 0xFF;
data[1] = (AudioInputUSB::features.volume>>8) & 0xFF;
}
else if (setup.bRequest==0x82) { // GET_MIN
//serial_print("vol get_min\n");
data[0] = 0; // min level is 0
data[1] = 0;
}
else if (setup.bRequest==0x83) { // GET_MAX
data[0] = FEATURE_MAX_VOLUME & 0xFF; // max level, for range of 0 to MAX
data[1] = (FEATURE_MAX_VOLUME>>8) & 0x0F;
}
else if (setup.bRequest==0x84) { // GET_RES
data[0] = 1; // increment vol by by 1
data[1] = 0;
}
else { // pass over SET_MEM, etc.
return 0;
}
*datalen = 2;
return 1;
}
}
return 0;
}
return 0;
}

int usb_audio_set_feature(void *stp, uint8_t *buf)
{
struct setup_struct setup = *((struct setup_struct *)stp);
if (setup.bmRequestType==0x21) { // should check bRequest too, and UnitID
if (setup.bChannel==0) {
if (setup.bCS==0x01) { // mute
if (setup.bRequest==0x01) { // SET_CUR
AudioInputUSB::features.mute = buf[0]; // 1=mute,0=unmute
AudioInputUSB::features.change = 1;
return 1;
}
}
else if (setup.bCS==0x02) { // volume
if (setup.bRequest==0x01) { // SET_CUR
AudioInputUSB::features.volume = buf[0] + (buf[1]<<8);
AudioInputUSB::features.change = 1;
return 1;
}
}
}
}
return 0;
}


#endif // F_CPU
#endif // AUDIO_INTERFACE

+ 43
- 0
teensy3/usb_audio.h View File

@@ -4,6 +4,8 @@
#include "usb_desc.h"
#ifdef AUDIO_INTERFACE

#define FEATURE_MAX_VOLUME 0xFFF // volume accepted from 0 to 0xFFF

#ifdef __cplusplus
extern "C" {
#endif
@@ -11,12 +13,48 @@ extern uint16_t usb_audio_receive_buffer[];
extern uint16_t usb_audio_transmit_buffer[];
extern void usb_audio_receive_callback(unsigned int len);
extern unsigned int usb_audio_transmit_callback(void);
int usb_audio_set_feature(void *stp, uint8_t *buf);
int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen);

extern uint32_t usb_audio_sync_feedback;
extern uint8_t usb_audio_receive_setting;
extern uint8_t usb_audio_transmit_setting;
#ifdef __cplusplus
}

// setup struct definition could be moved from usb_dev.c to usb_dev.h so we can reuse
// it instead of redefining it here
struct setup_struct {
union {
struct {
uint8_t bmRequestType;
uint8_t bRequest;
union {
struct {
uint8_t bChannel; // 0=main, 1=left, 2=right
uint8_t bCS; // Control Selector
};
uint16_t wValue;
};
union {
struct {
uint8_t bIfEp; // type of entity
uint8_t bEntityId; // UnitID, TerminalID, etc.
};
uint16_t wIndex;
};
uint16_t wLength;
};
};
};

// audio features supported
struct usb_audio_features_struct {
int change; // set to 1 when any value is changed
int mute; // 1=mute, 0=unmute
int volume; // volume from 0 to FEATURE_MAX_VOLUME, maybe should be float from 0.0 to 1.0
};

#include "AudioStream.h"

class AudioInputUSB : public AudioStream
@@ -26,6 +64,11 @@ public:
virtual void update(void);
void begin(void);
friend void usb_audio_receive_callback(unsigned int len);
friend int usb_audio_set_feature(void *stp, uint8_t *buf);
friend int usb_audio_get_feature(void *stp, uint8_t *data, uint32_t *datalen);

static struct usb_audio_features_struct features;

private:
static bool update_responsibility;
static audio_block_t *incoming_left;

+ 13
- 2
teensy3/usb_desc.c View File

@@ -416,7 +416,7 @@ static uint8_t flightsim_report_desc[] = {

#define AUDIO_INTERFACE_DESC_POS KEYMEDIA_INTERFACE_DESC_POS+KEYMEDIA_INTERFACE_DESC_SIZE
#ifdef AUDIO_INTERFACE
#define AUDIO_INTERFACE_DESC_SIZE 9+10+12+9+12+9 + 9+9+7+11+9+7 + 9+9+7+11+9+7+9
#define AUDIO_INTERFACE_DESC_SIZE 9+10+12+9+12+10+9 + 9+9+7+11+9+7 + 9+9+7+11+9+7+9
#else
#define AUDIO_INTERFACE_DESC_SIZE 0
#endif
@@ -920,6 +920,17 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
0x03, 0x00, // wChannelConfig, 0x0003 = Left & Right Front
0, // iChannelNames
0, // iTerminal
// Volume feature descriptor
10, // bLength
0x24, // bDescriptorType = CS_INTERFACE
0x06, // bDescriptorSubType = FEATURE_UNIT
0x31, // bUnitID
0x03, // bSourceID (Input Terminal)
0x01, // bControlSize (each channel is 1 byte, 3 channels)
0x03, // bmaControls(0) Master: Volume & Mute
0x00, // bmaControls(1) Left: None
0x00, // bmaControls(2) Right: None
0x00, // iFeature
// Output Terminal Descriptor
// USB DCD for Audio Devices 1.0, Table 4-4, page 40
9, // bLength
@@ -929,7 +940,7 @@ static uint8_t config_descriptor[CONFIG_DESC_SIZE] = {
//0x02, 0x03, // wTerminalType, 0x0302 = Headphones
0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio
0, // bAssocTerminal, 0 = unidirectional
3, // bCSourceID, connected to input terminal, ID=3
0x31, // bCSourceID, connected to feature, ID=31
0, // iTerminal
// Standard AS Interface Descriptor
// USB DCD for Audio Devices 1.0, Section 4.5.1, Table 4-18, page 59

+ 19
- 3
teensy3/usb_dev.c View File

@@ -415,8 +415,25 @@ static void usb_setup(void)
return;
}
break;
case 0x0122: // SET_CUR (wValue=0, wIndex=interface, wLength=len)
case 0x0121: // SET FEATURE
case 0x0221:
case 0x0321:
case 0x0421:
// handle these on the next packet. See usb_audio_set_feature()
return;
case 0x81A1: // GET FEATURE
case 0x82A1:
case 0x83A1:
case 0x84A1:
if (usb_audio_get_feature(&setup, reply_buffer, &datalen)) {
data = reply_buffer;
}
else {
endpoint0_stall();
return;
}
break;

case 0x81A2: // GET_CUR (wValue=0, wIndex=interface, wLength=len)
if (setup.wLength >= 3) {
reply_buffer[0] = 44100 & 255;
@@ -574,8 +591,7 @@ static void usb_control(uint32_t stat)
}
#endif
#ifdef AUDIO_INTERFACE
if (setup.wRequestAndType == 0x0122 /* SET_CUR */) {
// TODO: actually check data, do something with it?
if (usb_audio_set_feature(&setup, buf)) {
endpoint0_transmit(NULL, 0);
}
#endif

Loading…
Cancel
Save