Browse Source

Add volume/mute feature to AudioInputUSB

Change descriptor and code to handle features for USB Audio
teensy4-core
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

uint16_t AudioInputUSB::incoming_count; uint16_t AudioInputUSB::incoming_count;
uint8_t AudioInputUSB::receive_flag; uint8_t AudioInputUSB::receive_flag;


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

#define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4))) #define DMABUFATTR __attribute__ ((section(".dmabuffers"), aligned (4)))
uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR; uint16_t usb_audio_receive_buffer[AUDIO_RX_SIZE/2] DMABUFATTR;
uint32_t usb_audio_sync_feedback DMABUFATTR; uint32_t usb_audio_sync_feedback DMABUFATTR;
return target * 4; 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 // F_CPU
#endif // AUDIO_INTERFACE #endif // AUDIO_INTERFACE

+ 43
- 0
teensy3/usb_audio.h View File

#include "usb_desc.h" #include "usb_desc.h"
#ifdef AUDIO_INTERFACE #ifdef AUDIO_INTERFACE


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

#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
#endif #endif
extern uint16_t usb_audio_transmit_buffer[]; extern uint16_t usb_audio_transmit_buffer[];
extern void usb_audio_receive_callback(unsigned int len); extern void usb_audio_receive_callback(unsigned int len);
extern unsigned int usb_audio_transmit_callback(void); 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 uint32_t usb_audio_sync_feedback;
extern uint8_t usb_audio_receive_setting; extern uint8_t usb_audio_receive_setting;
extern uint8_t usb_audio_transmit_setting; extern uint8_t usb_audio_transmit_setting;
#ifdef __cplusplus #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" #include "AudioStream.h"


class AudioInputUSB : public AudioStream class AudioInputUSB : public AudioStream
virtual void update(void); virtual void update(void);
void begin(void); void begin(void);
friend void usb_audio_receive_callback(unsigned int len); 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: private:
static bool update_responsibility; static bool update_responsibility;
static audio_block_t *incoming_left; static audio_block_t *incoming_left;

+ 13
- 2
teensy3/usb_desc.c View File



#define AUDIO_INTERFACE_DESC_POS KEYMEDIA_INTERFACE_DESC_POS+KEYMEDIA_INTERFACE_DESC_SIZE #define AUDIO_INTERFACE_DESC_POS KEYMEDIA_INTERFACE_DESC_POS+KEYMEDIA_INTERFACE_DESC_SIZE
#ifdef AUDIO_INTERFACE #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 #else
#define AUDIO_INTERFACE_DESC_SIZE 0 #define AUDIO_INTERFACE_DESC_SIZE 0
#endif #endif
0x03, 0x00, // wChannelConfig, 0x0003 = Left & Right Front 0x03, 0x00, // wChannelConfig, 0x0003 = Left & Right Front
0, // iChannelNames 0, // iChannelNames
0, // iTerminal 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 // Output Terminal Descriptor
// USB DCD for Audio Devices 1.0, Table 4-4, page 40 // USB DCD for Audio Devices 1.0, Table 4-4, page 40
9, // bLength 9, // bLength
//0x02, 0x03, // wTerminalType, 0x0302 = Headphones //0x02, 0x03, // wTerminalType, 0x0302 = Headphones
0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio 0x02, 0x06, // wTerminalType, 0x0602 = Digital Audio
0, // bAssocTerminal, 0 = unidirectional 0, // bAssocTerminal, 0 = unidirectional
3, // bCSourceID, connected to input terminal, ID=3
0x31, // bCSourceID, connected to feature, ID=31
0, // iTerminal 0, // iTerminal
// Standard AS Interface Descriptor // Standard AS Interface Descriptor
// USB DCD for Audio Devices 1.0, Section 4.5.1, Table 4-18, page 59 // USB DCD for Audio Devices 1.0, Section 4.5.1, Table 4-18, page 59

+ 19
- 3
teensy3/usb_dev.c View File

return; return;
} }
break; 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; 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) case 0x81A2: // GET_CUR (wValue=0, wIndex=interface, wLength=len)
if (setup.wLength >= 3) { if (setup.wLength >= 3) {
reply_buffer[0] = 44100 & 255; reply_buffer[0] = 44100 & 255;
} }
#endif #endif
#ifdef AUDIO_INTERFACE #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); endpoint0_transmit(NULL, 0);
} }
#endif #endif

Loading…
Cancel
Save