821 lines
30 KiB
C
821 lines
30 KiB
C
|
#include "includes.h"
|
||
|
#include "asm/includes.h"
|
||
|
#include "app_config.h"
|
||
|
#include "system/timer.h"
|
||
|
#include "device/ioctl_cmds.h"
|
||
|
#include "device_drive.h"
|
||
|
#if TCFG_HOST_AUDIO_ENABLE
|
||
|
#include "usb/host/usb_host.h"
|
||
|
#include "usb_ctrl_transfer.h"
|
||
|
#include "usb_bulk_transfer.h"
|
||
|
#include "audio.h"
|
||
|
#include "usb_config.h"
|
||
|
|
||
|
#define LOG_TAG_CONST USB
|
||
|
#define LOG_TAG "[AUDIO]"
|
||
|
#define LOG_ERROR_ENABLE
|
||
|
#define LOG_DEBUG_ENABLE
|
||
|
#define LOG_INFO_ENABLE
|
||
|
/* #define LOG_DUMP_ENABLE */
|
||
|
#define LOG_CLI_ENABLE
|
||
|
#include "debug.h"
|
||
|
|
||
|
|
||
|
/* #define USB_AUDIO_PLAY_TEST */
|
||
|
|
||
|
struct usb_audio_play {
|
||
|
u32 sample_rate;
|
||
|
u8 Cur_AlternateSetting;
|
||
|
u8 src_channel;
|
||
|
u8 play_state;
|
||
|
u8 mute;
|
||
|
u8 *send_buf;
|
||
|
u8 *usb_audio_play_buf;
|
||
|
u8 *usb_audio_play_buf2;
|
||
|
cbuffer_t usb_audio_play_cbuf;
|
||
|
u32 usb_audio_remain_len;
|
||
|
OS_SEM sem;
|
||
|
int (*put_buf)(void *ptr, u32 len);
|
||
|
};
|
||
|
struct usb_audio_mic {
|
||
|
u8 Cur_AlternateSetting;
|
||
|
u32 sample_rate;
|
||
|
u8 record_state;
|
||
|
u8 *usb_audio_record_buf;
|
||
|
u8 *usb_audio_record_buf2;
|
||
|
cbuffer_t usb_audio_record_cbuf;
|
||
|
int *(*get_buf)(void *ptr, u32 len);
|
||
|
};
|
||
|
struct usb_audio_info {
|
||
|
usb_dev usb_id;
|
||
|
struct usb_audio_play player;
|
||
|
struct usb_audio_mic microphone;
|
||
|
};
|
||
|
|
||
|
enum {
|
||
|
AUDIO_PLAY_IDLE = 0,
|
||
|
AUDIO_PLAY_START,
|
||
|
AUDIO_PLAY_STOP,
|
||
|
AUDIO_PLAY_PAUSE,
|
||
|
};
|
||
|
enum {
|
||
|
AUDIO_RECORD_IDLE = 0,
|
||
|
AUDIO_RECORD_START,
|
||
|
AUDIO_RECORD_STOP,
|
||
|
AUDIO_RECORD_PAUSE,
|
||
|
};
|
||
|
|
||
|
#define EP_MAX_PACKET_SIZE (192)
|
||
|
|
||
|
struct usb_audio_info _usb_audio_info = {0};
|
||
|
#define __this (&_usb_audio_info)
|
||
|
|
||
|
struct audio_device_t audio_device[USB_MAX_HW_NUM][MAX_HOST_INTERFACE];
|
||
|
|
||
|
static u8 ep_in_dma_buf[256] __attribute__((aligned(4)));
|
||
|
static u8 ep_out_dma_buf[256] __attribute__((aligned(4)));
|
||
|
|
||
|
static int set_power(struct usb_host_device *host_dev, u32 value)
|
||
|
{
|
||
|
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
return DEV_ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static int get_power(struct usb_host_device *host_dev, u32 value)
|
||
|
{
|
||
|
return DEV_ERR_NONE;
|
||
|
}
|
||
|
|
||
|
static const struct interface_ctrl uac_ctrl = {
|
||
|
.interface_class = USB_CLASS_AUDIO,
|
||
|
.set_power = set_power,
|
||
|
.get_power = get_power,
|
||
|
.ioctl = NULL,
|
||
|
};
|
||
|
|
||
|
static const struct usb_interface_info _uac_if[USB_MAX_HW_NUM][MAX_HOST_INTERFACE] = {
|
||
|
{
|
||
|
{
|
||
|
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||
|
.dev.audio = &audio_device[0][0],
|
||
|
},
|
||
|
{
|
||
|
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||
|
.dev.audio = &audio_device[0][1],
|
||
|
},
|
||
|
{
|
||
|
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||
|
.dev.audio = &audio_device[0][2],
|
||
|
},
|
||
|
{
|
||
|
.ctrl = (struct interface_ctrl *) &uac_ctrl,
|
||
|
.dev.audio = &audio_device[0][3],
|
||
|
},
|
||
|
},
|
||
|
};
|
||
|
|
||
|
int usb_audio_parser(struct usb_host_device *host_dev, u8 interface_num, const u8 *pBuf)
|
||
|
{
|
||
|
struct usb_interface_descriptor *interface = (struct usb_interface_descriptor *)pBuf;
|
||
|
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
|
||
|
const struct usb_interface_info *usb_if = &_uac_if[usb_id][interface_num];
|
||
|
struct audio_streaming_t *as_t = NULL;
|
||
|
memset(usb_if->dev.p, 0, sizeof(struct audio_device_t));
|
||
|
host_dev->interface_info[interface_num] = usb_if;
|
||
|
usb_if->dev.audio->parent = host_dev;
|
||
|
|
||
|
if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOCONTROL) {
|
||
|
log_info("audio control interface : %d\n", interface_num);
|
||
|
pBuf += sizeof(struct usb_interface_descriptor);
|
||
|
usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
|
||
|
usb_if->dev.audio->interface_num = interface_num;
|
||
|
|
||
|
return sizeof(struct usb_interface_descriptor);
|
||
|
}
|
||
|
|
||
|
if (interface->bInterfaceSubClass == USB_SUBCLASS_AUDIOSTREAMING) {
|
||
|
usb_if->dev.audio->subclass = interface->bInterfaceSubClass;
|
||
|
usb_if->dev.audio->interface_num = interface_num;
|
||
|
if (interface->bNumEndpoints == 0) {
|
||
|
pBuf += sizeof(struct usb_interface_descriptor);
|
||
|
do {
|
||
|
struct usb_interface_descriptor *as_interface = (struct usb_interface_descriptor *)pBuf;
|
||
|
if (as_interface->bNumEndpoints == 0 || as_interface->bInterfaceClass != USB_CLASS_AUDIO) {
|
||
|
break;
|
||
|
}
|
||
|
log_info("audio streaming interface : %d ep_num:%d Altersetting:%d", interface_num, as_interface->bNumEndpoints, as_interface->bAlternateSetting);
|
||
|
as_t = &usb_if->dev.audio->as[as_interface->bAlternateSetting - 1];
|
||
|
as_t->bNumEndpoints = as_interface->bNumEndpoints;
|
||
|
pBuf += (USB_DT_INTERFACE_SIZE + UAC_DT_AS_HEADER_SIZE);
|
||
|
//解析format
|
||
|
struct uac_format_type_i_discrete_descriptor *uac_format_desc = (struct uac_format_type_i_discrete_descriptor *)pBuf;
|
||
|
if (uac_format_desc->bDescriptorSubtype == UAC_FORMAT_TYPE) {
|
||
|
as_t->bFormatType = uac_format_desc->bFormatType;
|
||
|
as_t->bNrChannels = uac_format_desc->bNrChannels;
|
||
|
as_t->bSubframeSize = uac_format_desc->bSubframeSize;
|
||
|
as_t->bBitResolution = uac_format_desc->bBitResolution;
|
||
|
as_t->bSamFreqType = uac_format_desc->bSamFreqType;
|
||
|
for (u8 i = 0; i < as_t->bSamFreqType; i++) {
|
||
|
memcpy(&as_t->tSamFreq[i], &uac_format_desc->tSamFreq[i], 3);
|
||
|
log_info("as bNrChannels:%d bBitResolution:%d tSamFreq : %d", as_t->bNrChannels, as_t->bBitResolution, as_t->tSamFreq[i]);
|
||
|
}
|
||
|
//Endpointdescriptor
|
||
|
pBuf += uac_format_desc->bLength;
|
||
|
/* for (int i = 0; i < as_t->bNumEndpoints; i++) { */
|
||
|
struct usb_endpoint_descriptor *endpoint = (struct usb_endpoint_descriptor *)pBuf;
|
||
|
if (endpoint->bDescriptorType == USB_DT_ENDPOINT) {
|
||
|
as_t->ep_Interval = endpoint->bInterval;
|
||
|
as_t->ep_max_packet_size = endpoint->wMaxPacketSize;
|
||
|
if (endpoint->bEndpointAddress & USB_DIR_IN) {
|
||
|
as_t->ep = endpoint->bEndpointAddress & 0xf;
|
||
|
log_info("ep in : %x\n", as_t->ep);
|
||
|
usb_if->dev.audio->support = MICROPHONE_SUPPORTED;
|
||
|
} else {
|
||
|
as_t->ep = endpoint->bEndpointAddress;
|
||
|
log_info("ep out : %x\n", as_t->ep);
|
||
|
usb_if->dev.audio->support = HEADPHONE_SUPPORTED;
|
||
|
}
|
||
|
pBuf += (USB_DT_ENDPOINT_AUDIO_SIZE + UAC_ISO_ENDPOINT_DESC_SIZE);
|
||
|
}
|
||
|
/* } */
|
||
|
} else {
|
||
|
log_error("uac_format_desc->bDescriptorSubtype err!!\n");
|
||
|
goto __exit;
|
||
|
}
|
||
|
|
||
|
} while (1);
|
||
|
/* log_info("lennnn:%d\n",pBuf - (u8 *)interface); */
|
||
|
return pBuf - (u8 *)interface ;
|
||
|
} else {
|
||
|
log_info("audio streaming interface : %d ep_num:%d Altersetting:%d\n", interface_num, interface->bNumEndpoints, interface->bAlternateSetting);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
__exit:
|
||
|
return USB_DT_INTERFACE_SIZE;
|
||
|
|
||
|
}
|
||
|
|
||
|
static struct audio_device_t *__find_microphone_interface(const struct usb_host_device *host_dev)
|
||
|
{
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
|
||
|
const struct usb_interface_info *usb_if = host_dev->interface_info[i];
|
||
|
if (usb_if &&
|
||
|
(usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
|
||
|
audio = usb_if->dev.audio;
|
||
|
if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
|
||
|
audio->support == MICROPHONE_SUPPORTED) {
|
||
|
// find microphone
|
||
|
return audio;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
static struct audio_device_t *__find_headphone_interface(const struct usb_host_device *host_dev)
|
||
|
{
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
for (u8 i = 0; i < MAX_HOST_INTERFACE; i++) {
|
||
|
const struct usb_interface_info *usb_if = host_dev->interface_info[i];
|
||
|
if (usb_if &&
|
||
|
(usb_if->ctrl->interface_class == USB_CLASS_AUDIO)) {
|
||
|
audio = usb_if->dev.audio;
|
||
|
if (audio->subclass == USB_SUBCLASS_AUDIOSTREAMING &&
|
||
|
audio->support == HEADPHONE_SUPPORTED) {
|
||
|
// find headphone
|
||
|
return audio;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
static u32 play_vol_convert(u16 v)
|
||
|
{
|
||
|
//固定音量表,更换声卡需要修改音量表
|
||
|
const u16 vol_table[] = {
|
||
|
//0-100
|
||
|
0xd300, //0
|
||
|
0xd58f, 0xd7bf, 0xd9a8, 0xdb5b, 0xdce1, 0xde45, 0xdf8a, 0xe0b6, 0xe1cd, 0xe2d1,
|
||
|
0xe3c5, 0xe4ab, 0xe583, 0xe651, 0xe714, 0xe7cd, 0xe87f, 0xe928, 0xe9ca, 0xea66,
|
||
|
0xeafc, 0xeb8d, 0xec18, 0xec9e, 0xed20, 0xed9e, 0xee18, 0xee8e, 0xef00, 0xef6f,
|
||
|
0xefdc, 0xf045, 0xf0ab, 0xf10f, 0xf171, 0xf1d0, 0xf22c, 0xf287, 0xf2e0, 0xf336,
|
||
|
0xf38b, 0xf3de, 0xf42f, 0xf47e, 0xf4cc, 0xf518, 0xf563, 0xf5ad, 0xf5f5, 0xf63c,
|
||
|
0xf681, 0xf6c6, 0xf709, 0xf74b, 0xf78c, 0xf7cb, 0xf80a, 0xf848, 0xf885, 0xf8c1,
|
||
|
0xf8fc, 0xf936, 0xf96f, 0xf9a8, 0xf9df, 0xfa16, 0xfa4c, 0xfa81, 0xfab6, 0xfaea,
|
||
|
0xfb1d, 0xfb50, 0xfb82, 0xfbb3, 0xfbe4, 0xfc14, 0xfc43, 0xfc72, 0xfca0, 0xfcce,
|
||
|
0xfcfc, 0xfd28, 0xfd55, 0xfd80, 0xfdab, 0xfdd6, 0xfe01, 0xfe2a, 0xfe54, 0xfe7d,
|
||
|
0xfea5, 0xfece, 0xfef5, 0xff1d, 0xff43, 0xff6a, 0xff90, 0xffb6, 0xffdb, 0x0000,
|
||
|
};
|
||
|
|
||
|
if (v <= 100) {
|
||
|
return vol_table[v];
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < sizeof(vol_table) / 2; i++) {
|
||
|
if (v <= vol_table[i]) {
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void set_usb_audio_play_volume(u16 vol)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||
|
u8 featureUnitID = 6;
|
||
|
usb_audio_volume_control(host_dev, featureUnitID, 1, play_vol_convert(vol));
|
||
|
usb_audio_volume_control(host_dev, featureUnitID, 2, play_vol_convert(vol));
|
||
|
if (vol == 0) {
|
||
|
__this->player.mute = 1;
|
||
|
usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute); //mute
|
||
|
} else {
|
||
|
if (__this->player.mute == 1) {
|
||
|
__this->player.mute = 0;
|
||
|
usb_audio_mute_control(host_dev, featureUnitID, __this->player.mute);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#ifdef USB_AUDIO_PLAY_TEST
|
||
|
static const s16 sin_48k[] = {
|
||
|
0, 2139, 4240, 6270, 8192, 9974, 11585, 12998,
|
||
|
14189, 15137, 15826, 16244, 16384, 16244, 15826, 15137,
|
||
|
14189, 12998, 11585, 9974, 8192, 6270, 4240, 2139,
|
||
|
0, -2139, -4240, -6270, -8192, -9974, -11585, -12998,
|
||
|
-14189, -15137, -15826, -16244, -16384, -16244, -15826, -15137,
|
||
|
-14189, -12998, -11585, -9974, -8192, -6270, -4240, -2139
|
||
|
};
|
||
|
#endif
|
||
|
static void usb_audio_tx_isr(struct usb_host_device *host_dev, u32 ep)
|
||
|
{
|
||
|
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
struct audio_streaming_t *as_t = NULL;
|
||
|
u16 ep_max_packet_size = 0;
|
||
|
u8 channel = 0;
|
||
|
u32 rlen = 0;
|
||
|
static u32 usb_audio_tx_len = 0;
|
||
|
|
||
|
if (__this->player.play_state != AUDIO_PLAY_START) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
audio = __find_headphone_interface(host_dev);
|
||
|
if (!audio) {
|
||
|
log_error("no find headphone interface!");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||
|
/* ep_max_packet_size = as_t->ep_max_packet_size; */
|
||
|
ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||
|
channel = as_t->bNrChannels;
|
||
|
|
||
|
//iso send
|
||
|
#ifdef USB_AUDIO_PLAY_TEST
|
||
|
//For Test
|
||
|
int tx_len = 0;
|
||
|
#if 1 // 单声道双声道输出
|
||
|
s16 buf[240 / 2];
|
||
|
for (u8 i = 0, j = 0; i < 240 / 2; i += 2) {
|
||
|
buf[i] = sin_48k[j];
|
||
|
buf[i + 1] = sin_48k[j];
|
||
|
j++;
|
||
|
if (j >= sizeof(sin_48k) / sizeof(sin_48k[0])) {
|
||
|
j = 0;
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
//单声道直接输出
|
||
|
u8 buf[248];
|
||
|
do {
|
||
|
memcpy(&buf[tx_len], sin_48k, sizeof(sin_48k));
|
||
|
tx_len += sizeof(sin_48k);
|
||
|
} while (tx_len < ep_max_packet_size);
|
||
|
#endif
|
||
|
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||
|
#else
|
||
|
if (__this->player.usb_audio_remain_len == 0) {
|
||
|
cbuf_read_alloc(&__this->player.usb_audio_play_cbuf, &__this->player.usb_audio_remain_len);
|
||
|
usb_audio_tx_len = 0;
|
||
|
}
|
||
|
if (__this->player.usb_audio_remain_len) {
|
||
|
if (usb_audio_tx_len == 0) {
|
||
|
rlen = cbuf_read(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf2, __this->player.usb_audio_remain_len);
|
||
|
if (!rlen) {
|
||
|
__this->player.usb_audio_remain_len = 0;
|
||
|
usb_audio_tx_len = 0;
|
||
|
putchar('C');
|
||
|
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
|
||
|
os_sem_post(&__this->player.sem);
|
||
|
return;
|
||
|
}
|
||
|
os_sem_post(&__this->player.sem);
|
||
|
|
||
|
}
|
||
|
u8 *send_buf = __this->player.send_buf;
|
||
|
u8 *play_buf = __this->player.usb_audio_play_buf2;
|
||
|
if (channel == 2) {
|
||
|
if (__this->player.src_channel == 1) {
|
||
|
//源数据是单声道数据,转双声道输出
|
||
|
int j = 0;
|
||
|
for (u8 i = 0; i < ep_max_packet_size; i += 4) {
|
||
|
//left
|
||
|
*(send_buf + i) = *(play_buf + (usb_audio_tx_len + j));
|
||
|
*(send_buf + i + 1) = *(play_buf + (usb_audio_tx_len + j + 1));
|
||
|
//right
|
||
|
|
||
|
*(send_buf + i + 2) = *(play_buf + (usb_audio_tx_len + j));
|
||
|
*(send_buf + i + 3) = *(play_buf + (usb_audio_tx_len + j + 1));
|
||
|
j += 2;
|
||
|
}
|
||
|
usb_audio_tx_len += j;
|
||
|
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, send_buf, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||
|
} else if (__this->player.src_channel == 2) {
|
||
|
//源数据是双声道数据,直接双声道输出
|
||
|
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, play_buf + usb_audio_tx_len, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 0);
|
||
|
usb_audio_tx_len += ep_max_packet_size;
|
||
|
}
|
||
|
} else if (channel == 1) {
|
||
|
}
|
||
|
if (usb_audio_tx_len >= __this->player.usb_audio_remain_len) {
|
||
|
__this->player.usb_audio_remain_len = 0;
|
||
|
usb_audio_tx_len = 0;
|
||
|
}
|
||
|
} else {
|
||
|
//audio buf null ,send null packet
|
||
|
putchar('E');
|
||
|
usb_h_ep_write_async(usb_id, ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1);
|
||
|
}
|
||
|
|
||
|
#endif
|
||
|
}
|
||
|
void set_vol_test(void *p)
|
||
|
{
|
||
|
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||
|
static u16 vol = 100;
|
||
|
set_usb_audio_play_volume(vol);
|
||
|
/* static u8 f = 0; */
|
||
|
/* void usb_audio_pause_play(void); */
|
||
|
/* void usb_audio_resume_play(void); */
|
||
|
/* if (!f) { */
|
||
|
/* usb_audio_pause_play(); */
|
||
|
/* } else { */
|
||
|
/* usb_audio_resume_play(); */
|
||
|
/* } */
|
||
|
/* f = !f; */
|
||
|
vol -= 10;
|
||
|
}
|
||
|
void audio_play_task(void *p)
|
||
|
{
|
||
|
log_info(">>> Enter usb audio play task");
|
||
|
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||
|
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
u8 *ptr = NULL;
|
||
|
u32 wlen = 0;
|
||
|
u32 ret = 0;
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
audio = __find_headphone_interface(host_dev);
|
||
|
struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||
|
/* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
|
||
|
u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||
|
log_info("ep max packet : %d\n", ep_max_packet_size);
|
||
|
if (__this->player.send_buf) {
|
||
|
free(__this->player.send_buf);
|
||
|
__this->player.send_buf = NULL;
|
||
|
}
|
||
|
__this->player.send_buf = zalloc(ep_max_packet_size);
|
||
|
u32 usb_audio_buf_size = ep_max_packet_size * 5; //预留5个包的缓存
|
||
|
|
||
|
/* sys_timer_add(host_dev,set_vol_test,5000); */
|
||
|
os_sem_create(&__this->player.sem, 0);
|
||
|
u32 host_ep = as_t->host_ep;
|
||
|
__this->player.play_state = AUDIO_PLAY_START;
|
||
|
//分配双缓存
|
||
|
// 一个缓存保存读卡的数据,一个用于usb发送
|
||
|
if (!__this->player.usb_audio_play_buf) {
|
||
|
__this->player.usb_audio_play_buf = zalloc(usb_audio_buf_size);
|
||
|
cbuf_init(&__this->player.usb_audio_play_cbuf, __this->player.usb_audio_play_buf, usb_audio_buf_size);
|
||
|
usb_h_ep_write_async(usb_id, host_ep, ep_max_packet_size, as_t->ep, NULL, ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //启动iso传输
|
||
|
}
|
||
|
if (!__this->player.usb_audio_play_buf2) {
|
||
|
__this->player.usb_audio_play_buf2 = zalloc(usb_audio_buf_size);
|
||
|
}
|
||
|
while (1) {
|
||
|
if (__this->player.Cur_AlternateSetting == 0 || __this->player.play_state != AUDIO_PLAY_START) {
|
||
|
putchar('C');
|
||
|
os_time_dly(50);
|
||
|
continue;
|
||
|
}
|
||
|
ptr = cbuf_write_alloc(&__this->player.usb_audio_play_cbuf, &wlen);
|
||
|
if (wlen) {
|
||
|
putchar('R');
|
||
|
ret = __this->player.put_buf(ptr, wlen);
|
||
|
if (ret != wlen) {
|
||
|
__this->player.play_state = AUDIO_PLAY_STOP;
|
||
|
goto __task_exit;
|
||
|
|
||
|
}
|
||
|
cbuf_write_updata(&__this->player.usb_audio_play_cbuf, wlen);
|
||
|
} else {
|
||
|
log_w("usb audio play buf not enough!\n");
|
||
|
}
|
||
|
__task_exit:
|
||
|
os_sem_pend(&__this->player.sem, 0);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void usb_audio_start_play(const usb_dev usb_id, u8 channel, u8 bit_reso, u32 sample_rate)
|
||
|
{
|
||
|
log_info(" usb audio play\n");
|
||
|
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
struct audio_streaming_t *as_t = NULL;
|
||
|
u8 *ep_buffer = ep_out_dma_buf;
|
||
|
u8 find_alternatesetting = 0;
|
||
|
audio = __find_headphone_interface(host_dev);
|
||
|
if (!audio) {
|
||
|
log_error("no find headphone interface!");
|
||
|
return;
|
||
|
}
|
||
|
for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
|
||
|
as_t = &audio->as[i];
|
||
|
if (as_t->bBitResolution == bit_reso) {
|
||
|
for (u8 j = 0; j < as_t->bSamFreqType; j++) {
|
||
|
if (as_t->tSamFreq[j] == sample_rate) {
|
||
|
find_alternatesetting = i + 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!find_alternatesetting) {
|
||
|
log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
__this->usb_id = usb_id;
|
||
|
//端点分配
|
||
|
u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_OUT, USB_ENDPOINT_XFER_ISOC);
|
||
|
ASSERT(host_ep != -1, "ep not enough");
|
||
|
|
||
|
__this->player.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
|
||
|
__this->player.sample_rate = sample_rate; //选择采样率
|
||
|
__this->player.src_channel = channel;
|
||
|
as_t = &audio->as[find_alternatesetting - 1];
|
||
|
u8 target_ep = as_t->ep;
|
||
|
u8 ep_interval = as_t->ep_Interval;
|
||
|
as_t->host_ep = host_ep;
|
||
|
|
||
|
usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface Alternatesetting
|
||
|
usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
|
||
|
//设置音量
|
||
|
/* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
|
||
|
/* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
|
||
|
|
||
|
log_info("H2D ep: %x --> %x interval: %d", host_ep, target_ep, ep_interval);
|
||
|
usb_h_set_ep_isr(host_dev, host_ep, usb_audio_tx_isr, host_dev);
|
||
|
usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_out_dma_buf));
|
||
|
task_create(audio_play_task, host_dev, "uac_play");
|
||
|
}
|
||
|
|
||
|
void usb_audio_stop_play(const usb_dev usb_id)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||
|
usb_h_set_ep_isr(NULL, 0, NULL, NULL);
|
||
|
__this->player.put_buf(NULL, 0);
|
||
|
__this->player.Cur_AlternateSetting = 0;
|
||
|
__this->player.sample_rate = 0;
|
||
|
__this->player.src_channel = 0;
|
||
|
if (__this->player.usb_audio_play_buf) {
|
||
|
free(__this->player.usb_audio_play_buf);
|
||
|
__this->player.usb_audio_play_buf = NULL;
|
||
|
}
|
||
|
if (__this->player.usb_audio_play_buf2) {
|
||
|
free(__this->player.usb_audio_play_buf2);
|
||
|
__this->player.usb_audio_play_buf2 = NULL;
|
||
|
}
|
||
|
if (__this->player.send_buf) {
|
||
|
free(__this->player.send_buf);
|
||
|
__this->player.send_buf = NULL;
|
||
|
}
|
||
|
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||
|
task_kill("uac_play");
|
||
|
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||
|
}
|
||
|
void usb_audio_pause_play(void)
|
||
|
{
|
||
|
__this->player.play_state = AUDIO_PLAY_PAUSE;
|
||
|
}
|
||
|
void usb_audio_resume_play(void)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||
|
struct audio_device_t *audio = __find_headphone_interface(host_dev);
|
||
|
struct audio_streaming_t *as_t = &audio->as[__this->player.Cur_AlternateSetting - 1];
|
||
|
__this->player.play_state = AUDIO_PLAY_START;
|
||
|
usb_h_ep_write_async(__this->usb_id, as_t->host_ep, as_t->ep_max_packet_size, as_t->ep, NULL, as_t->ep_max_packet_size, USB_ENDPOINT_XFER_ISOC, 1); //重新启动传输
|
||
|
}
|
||
|
|
||
|
|
||
|
static u32 record_vol_convert(u16 v)
|
||
|
{
|
||
|
//固定音量表,更换声卡需要修改音量表
|
||
|
const u16 vol_table[] = {
|
||
|
//0-100
|
||
|
0xf400,
|
||
|
0xf479, 0xf4ee, 0xf560, 0xf5cf, 0xf63a, 0xf6a3, 0xf709, 0xf76c, 0xf7cd, 0xf82b,
|
||
|
0xf887, 0xf8e1, 0xf939, 0xf98f, 0xf9e4, 0xfa36, 0xfa87, 0xfad6, 0xfb23, 0xfb6f,
|
||
|
0xfbba, 0xfc03, 0xfc4b, 0xfc91, 0xfcd6, 0xfd1a, 0xfd5d, 0xfd9f, 0xfde0, 0xfe1f,
|
||
|
0xfe5e, 0xfe9b, 0xfed8, 0xff14, 0xff4e, 0xff88, 0xffc1, 0xfff9, 0x0003, 0x0069,
|
||
|
0x00a3, 0x00de, 0x0119, 0x0155, 0x0193, 0x01d1, 0x0210, 0x0251, 0x0292, 0x02d5,
|
||
|
0x0318, 0x035d, 0x03a3, 0x03eb, 0x0434, 0x047e, 0x04c9, 0x0517, 0x0565, 0x05b5,
|
||
|
0x0607, 0x065b, 0x06b1, 0x0708, 0x0762, 0x07bd, 0x081b, 0x087c, 0x08de, 0x0943,
|
||
|
0x09ab, 0x0a16, 0x0a84, 0x0af4, 0x0b69, 0x0be1, 0x0c5c, 0x0cdc, 0x0d60, 0x0de9,
|
||
|
0x0e77, 0x0f0a, 0x0fa2, 0x1041, 0x10e7, 0x1195, 0x124a, 0x1308, 0x13d0, 0x14a3,
|
||
|
0x1582, 0x166e, 0x176a, 0x1877, 0x1998, 0x1ad0, 0x1c24, 0x1d98, 0x1f33, 0x2100,
|
||
|
};
|
||
|
|
||
|
if (v <= 100) {
|
||
|
return vol_table[v];
|
||
|
}
|
||
|
|
||
|
for (int i = 0; i < sizeof(vol_table) / 2; i++) {
|
||
|
if (v <= vol_table[i]) {
|
||
|
return i;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void set_usb_audio_record_volume(u16 vol)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||
|
u8 featureUnitID = 5;
|
||
|
usb_audio_volume_control(host_dev, featureUnitID, 0, record_vol_convert(vol));
|
||
|
}
|
||
|
|
||
|
static u32 write_file_len = 0;
|
||
|
static void usb_audio_rx_isr(struct usb_host_device *host_dev, u32 ep)
|
||
|
{
|
||
|
u8 buffer[192] = {0};
|
||
|
u8 *ptr = NULL;
|
||
|
int rlen, wlen = 0;
|
||
|
usb_dev usb_id = host_device2id(host_dev);
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
struct audio_streaming_t *as_t = NULL;
|
||
|
audio = __find_microphone_interface(host_dev);
|
||
|
if (!audio) {
|
||
|
log_error("no find microphone interface!");
|
||
|
return;
|
||
|
}
|
||
|
if (__this->microphone.record_state != AUDIO_RECORD_START) {
|
||
|
return;
|
||
|
}
|
||
|
as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||
|
u8 channel = as_t->bNrChannels;
|
||
|
|
||
|
u32 rx_len = usb_h_ep_read_async(usb_id, ep, as_t->ep, buffer, sizeof(buffer), USB_ENDPOINT_XFER_ISOC, 0);
|
||
|
/* g_printf("RX:%d\n",rx_len); */
|
||
|
/* printf_buf(buffer, rx_len); */
|
||
|
cbuf_write(&__this->microphone.usb_audio_record_cbuf, buffer, rx_len);
|
||
|
cbuf_write_alloc(&__this->microphone.usb_audio_record_cbuf, &wlen);
|
||
|
if (wlen == 0) {
|
||
|
putchar('O');
|
||
|
if (write_file_len) {
|
||
|
log_w("write againnnnn\n");
|
||
|
}
|
||
|
/* [> printf("R:%d W:%d\n", rx_len,wlen); <] */
|
||
|
cbuf_read_alloc(&__this->microphone.usb_audio_record_cbuf, &rlen);
|
||
|
cbuf_read(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf2, rlen);
|
||
|
write_file_len = rlen;
|
||
|
os_taskq_post_msg("uac_record", 2, 0x01, rlen);
|
||
|
/* return; */
|
||
|
}
|
||
|
|
||
|
usb_h_ep_read_async(usb_id, ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //触发下一个接收中断
|
||
|
}
|
||
|
void audio_record_task(void *p)
|
||
|
{
|
||
|
log_info(">>> Enter usb audio record task");
|
||
|
struct usb_host_device *host_dev = (struct usb_host_device *)p;
|
||
|
const usb_dev usb_id = host_device2id(host_dev);
|
||
|
u8 *ptr = NULL;
|
||
|
u32 rlen = 0;
|
||
|
u32 ret = 0;
|
||
|
int msg[16];
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
audio = __find_microphone_interface(host_dev);
|
||
|
struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||
|
/* u32 ep_max_packet_size = as_t->ep_max_packet_size; */
|
||
|
u32 ep_max_packet_size = EP_MAX_PACKET_SIZE;
|
||
|
log_info("ep max packet : %d\n", ep_max_packet_size);
|
||
|
u32 usb_audio_buf_size = ep_max_packet_size * 50;
|
||
|
|
||
|
u32 host_ep = as_t->host_ep;
|
||
|
u8 target_ep = as_t->ep;
|
||
|
//分配双缓存
|
||
|
// 一个缓存写卡的数据,一个用于usb接收
|
||
|
if (!__this->microphone.usb_audio_record_buf) {
|
||
|
__this->microphone.usb_audio_record_buf = zalloc(usb_audio_buf_size);
|
||
|
cbuf_init(&__this->microphone.usb_audio_record_cbuf, __this->microphone.usb_audio_record_buf, usb_audio_buf_size);
|
||
|
|
||
|
}
|
||
|
if (!__this->microphone.usb_audio_record_buf2) {
|
||
|
__this->microphone.usb_audio_record_buf2 = zalloc(usb_audio_buf_size);
|
||
|
}
|
||
|
|
||
|
usb_h_ep_read_async(usb_id, host_ep, target_ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //启动iso
|
||
|
while (1) {
|
||
|
ret = __os_taskq_pend(msg, ARRAY_SIZE(msg), portMAX_DELAY);
|
||
|
if (ret == OS_TASKQ) {
|
||
|
switch (msg[1]) {
|
||
|
case 0x01:
|
||
|
ptr = __this->microphone.usb_audio_record_buf2;
|
||
|
rlen = msg[2];
|
||
|
putchar('W');
|
||
|
__this->microphone.get_buf(ptr, rlen);
|
||
|
write_file_len = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
void usb_audio_start_record(const usb_dev usb_id, u8 bit_reso, u32 sample_rate)
|
||
|
{
|
||
|
log_info(" usb audio record\n");
|
||
|
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||
|
struct audio_device_t *audio = NULL;
|
||
|
struct audio_streaming_t *as_t = NULL;
|
||
|
u8 *ep_buffer = ep_in_dma_buf;
|
||
|
u8 find_alternatesetting = 0;
|
||
|
audio = __find_microphone_interface(host_dev);
|
||
|
if (!audio) {
|
||
|
log_error("no find microphone interface!");
|
||
|
return;
|
||
|
}
|
||
|
for (u8 i = 0; i < ARRAY_SIZE(audio->as); i++) {
|
||
|
as_t = &audio->as[i];
|
||
|
if (as_t->bBitResolution == bit_reso) {
|
||
|
for (u8 j = 0; j < as_t->bSamFreqType; j++) {
|
||
|
if (as_t->tSamFreq[j] == sample_rate) {
|
||
|
find_alternatesetting = i + 1;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
if (!find_alternatesetting) {
|
||
|
log_e("can not find Alternatesetting,please check bit_reso and sample_rate\n");
|
||
|
return;
|
||
|
}
|
||
|
//端点分配
|
||
|
u32 host_ep = usb_get_ep_num(usb_id, USB_DIR_IN, USB_ENDPOINT_XFER_ISOC);
|
||
|
ASSERT(host_ep != -1, "ep not enough");
|
||
|
__this->usb_id = usb_id;
|
||
|
host_ep = host_ep | USB_DIR_IN;
|
||
|
|
||
|
__this->microphone.Cur_AlternateSetting = find_alternatesetting; //选择Alternatesetting
|
||
|
__this->microphone.sample_rate = sample_rate; //选择采样率
|
||
|
as_t = &audio->as[find_alternatesetting - 1];
|
||
|
u8 target_ep = as_t->ep;
|
||
|
u8 ep_interval = as_t->ep_Interval;
|
||
|
as_t->host_ep = host_ep;
|
||
|
|
||
|
usb_set_interface(host_dev, audio->interface_num, find_alternatesetting); //interface 1 Alternatesetting 1
|
||
|
usb_audio_sampling_frequency_control(host_dev, target_ep, sample_rate);//设置采样率
|
||
|
//设置音量
|
||
|
/* usb_audio_volume_control(host_dev, 6, 1, vol_convert(5)); */
|
||
|
/* usb_audio_volume_control(host_dev, 6, 2, vol_convert(5)); */
|
||
|
log_info("D2H ep: %x --> %x", target_ep, host_ep);
|
||
|
usb_h_set_ep_isr(host_dev, host_ep, usb_audio_rx_isr, host_dev);
|
||
|
usb_h_ep_config(usb_id, host_ep, USB_ENDPOINT_XFER_ISOC, 1, ep_interval, ep_buffer, sizeof(ep_in_dma_buf));
|
||
|
task_create(audio_record_task, host_dev, "uac_record");
|
||
|
__this->microphone.record_state = AUDIO_RECORD_START;
|
||
|
}
|
||
|
void usb_audio_stop_record(const usb_dev usb_id)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(usb_id);
|
||
|
usb_h_set_ep_isr(NULL, 0, NULL, NULL);
|
||
|
__this->microphone.get_buf(NULL, 0);
|
||
|
__this->microphone.Cur_AlternateSetting = 0;
|
||
|
__this->microphone.sample_rate = 0;
|
||
|
if (__this->microphone.usb_audio_record_buf) {
|
||
|
free(__this->microphone.usb_audio_record_buf);
|
||
|
__this->microphone.usb_audio_record_buf = NULL;
|
||
|
}
|
||
|
if (__this->microphone.usb_audio_record_buf2) {
|
||
|
free(__this->microphone.usb_audio_record_buf2);
|
||
|
__this->microphone.usb_audio_record_buf2 = NULL;
|
||
|
}
|
||
|
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||
|
task_kill("uac_record");
|
||
|
printf("\n[ debug ]--func=%s line=%d\n", __func__, __LINE__);
|
||
|
}
|
||
|
void usb_audio_pause_record(void)
|
||
|
{
|
||
|
__this->microphone.record_state = AUDIO_RECORD_PAUSE;
|
||
|
}
|
||
|
void usb_audio_resume_record(void)
|
||
|
{
|
||
|
const struct usb_host_device *host_dev = host_id2device(__this->usb_id);
|
||
|
struct audio_device_t *audio = __find_microphone_interface(host_dev);
|
||
|
struct audio_streaming_t *as_t = &audio->as[__this->microphone.Cur_AlternateSetting - 1];
|
||
|
__this->microphone.record_state = AUDIO_RECORD_START;
|
||
|
usb_h_ep_read_async(__this->usb_id, as_t->host_ep, as_t->ep, NULL, 0, USB_ENDPOINT_XFER_ISOC, 1); //重新启动接收
|
||
|
}
|
||
|
|
||
|
void usb_audio_start_process(u32 id)
|
||
|
{
|
||
|
usb_audio_start_play(id, 1, 16, 48000); //开启headphone
|
||
|
usb_audio_start_record(id, 16, 48000); //开启microphone
|
||
|
}
|
||
|
void usb_audio_stop_process(u32 id)
|
||
|
{
|
||
|
usb_audio_stop_play(id);
|
||
|
usb_audio_stop_record(id);
|
||
|
}
|
||
|
|
||
|
|
||
|
static void usb_audio_event_handler(struct sys_event *event, void *priv)
|
||
|
{
|
||
|
const char *audio = NULL;
|
||
|
switch (event->type) {
|
||
|
case SYS_DEVICE_EVENT:
|
||
|
if ((u32)event->arg == DEVICE_EVENT_FROM_USB_HOST) {
|
||
|
if ((event->u.dev.event == DEVICE_EVENT_IN) ||
|
||
|
(event->u.dev.event == DEVICE_EVENT_CHANGE)) {
|
||
|
audio = (const char *)event->u.dev.value;
|
||
|
usb_audio_start_process(audio[5] - '0');
|
||
|
|
||
|
} else if (event->u.dev.event == DEVICE_EVENT_OUT) {
|
||
|
log_error("device out %x", event->u.dev.value);
|
||
|
usb_audio_stop_process(audio[5] - '0');
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
void usb_host_audio_init(int (*put_buf)(void *ptr, u32 len), int *(*get_buf)(void *ptr, u32 len))
|
||
|
{
|
||
|
memset(__this, 0, sizeof(struct usb_audio_info));
|
||
|
__this->player.put_buf = put_buf;
|
||
|
__this->microphone.get_buf = get_buf;
|
||
|
register_sys_event_handler(SYS_DEVICE_EVENT, DEVICE_EVENT_FROM_USB_HOST, 2,
|
||
|
usb_audio_event_handler);
|
||
|
}
|
||
|
void usb_host_audio_exit()
|
||
|
{
|
||
|
unregister_sys_event_handler(usb_audio_event_handler);
|
||
|
__this->player.put_buf = NULL;
|
||
|
__this->microphone.get_buf = NULL;
|
||
|
}
|
||
|
|
||
|
#endif
|