/* * Copyright (c) 2022, sakumisu * * SPDX-License-Identifier: Apache-2.0 */ #include "rtthread.h" #ifdef RT_USBH_UAC #include "basic_include.h" #include "rttusb_host.h" #include "usbh_audio.h" #define DEV_FORMAT "/dev/audio%d" /* general descriptor field offsets */ #define DESC_bLength 0 /** Length offset */ #define DESC_bDescriptorType 1 /** Descriptor type offset */ #define DESC_bDescriptorSubType 2 /** Descriptor subtype offset */ /* interface descriptor field offsets */ #define INTF_DESC_bInterfaceNumber 2 /** Interface number offset */ #define INTF_DESC_bAlternateSetting 3 /** Alternate setting offset */ #define AUDIO_FREE_PIPE 0 #define AUDIO_ALLOC_PIPE 1 #define AUDIO_MIC_EN 1 //应用层MIC使能 #define AUDIO_SPK_EN 1 //应用层SPK使能 #define AUDIO_VOLUME_CONTROL_EN 0 //UAC音量控制使能 (根据设备是否支持该功能,自行选择打开) #define AUDIO_SET_INTF_ALTSETTING 1 /* ---------------------------- MIC ---------------------------- */ #define AUDIO_MIC_SAMPLING_FREQ 8000 //设置MIC接收的采样率 #define AUDIO_MIC_RESOLUTION_BITS 16 //设置MIC接收的采样精度 #define AUDIO_MIC_MODULE_CHANNEL 1 //设置MIC接收的通道数 #define AUDIO_MIC_RESOLUTION_BYTES (AUDIO_MIC_RESOLUTION_BITS / 8) #define AUDIO_RX_PACKET_SIZE ((AUDIO_MIC_SAMPLING_FREQ * AUDIO_MIC_MODULE_CHANNEL * AUDIO_MIC_RESOLUTION_BYTES) / 1000) //计算MIC每毫秒接收的数据包大小 /* ---------------------------- SPK ---------------------------- */ #define AUDIO_SPK_SAMPLING_FREQ 8000 //设置SPK发送的采样率 #define AUDIO_SPK_RESOLUTION_BITS 16 //设置SPK发送的采样精度 #define AUDIO_SPK_MODULE_CHANNEL 1 //设置SPK发送的通道数 #define AUDIO_SPK_RESOLUTION_BYTES (AUDIO_SPK_RESOLUTION_BITS / 8) #define AUDIO_TX_PACKET_SIZE ((AUDIO_SPK_SAMPLING_FREQ * AUDIO_SPK_MODULE_CHANNEL * AUDIO_SPK_RESOLUTION_BYTES) / 1000) //计算SPK每毫秒发送的数据包大小 extern uint32 usbmic_packet_len; extern uint8_t uac_run; extern uint8_t uac_open; static int usb_dma_uac_irq_times = 0; static struct uclass_driver usbh_audio_class; rt_uint8_t g_audio_buf[128]; struct usbh_audio g_audio_class[CONFIG_USBHOST_MAX_AUDIO_CLASS]; static rt_uint32_t g_devinuse = 0; static struct usbh_audio *usbh_audio_class_alloc(void) { int devno; for (devno = 0; devno < CONFIG_USBHOST_MAX_AUDIO_CLASS; devno++) { if ((g_devinuse & (1 << devno)) == 0) { g_devinuse |= (1 << devno); memset(&g_audio_class[devno], 0, sizeof(struct usbh_audio)); g_audio_class[devno].minor = devno; return &g_audio_class[devno]; } } return RT_NULL; } static void usbh_audio_class_free(struct usbh_audio *audio_class) { int devno = audio_class->minor; if (devno >= 0 && devno < 32) { g_devinuse &= ~(1 << devno); } memset(audio_class, 0, sizeof(struct usbh_audio)); } int usbh_audio_open(struct usbh_audio *audio_class, const char *name, rt_uint32_t samp_freq) { struct urequest setup; struct uendpoint_descriptor *ep_desc = RT_NULL; rt_uint8_t intf = 0xff; rt_uint8_t altsetting = 1; int timeout = USB_TIMEOUT_BASIC; // if (audio_class->is_opened) { // return 0; // } for (rt_uint8_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { printf("audio_class->module[%d]\n",i); for (rt_uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) { for (rt_uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) { if (audio_class->module[i].altsetting[j].sampfreq[k] == samp_freq) { intf = audio_class->module[i].data_intf; altsetting = j; printf("usb host audio open:%d %d\n",intf,altsetting); goto freq_found; } } } } } return -EIO; freq_found: setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE; setup.bRequest = USB_REQ_SET_INTERFACE; setup.wValue = altsetting; setup.wIndex = intf; setup.wLength = 0; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RET_ERR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RET_ERR; } if (strcmp(name, "mic") == 0) { ep_desc = &audio_class->isoin; } else if (strcmp(name, "speaker") == 0) { ep_desc = &audio_class->isoout; } setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_ENDPOINT; setup.bRequest = SET_CUR; setup.wValue = (SAMPLING_FREQ_CONTROL << 8) | 0x00; setup.wIndex = ep_desc->bEndpointAddress; setup.wLength = 3; memcpy(g_audio_buf, &samp_freq, 3); if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RET_ERR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 3, timeout) != 3) { return RET_ERR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RET_ERR; } os_printf("Open audio module :%s, altsetting: %u\r\n", name, altsetting); audio_class->is_opened = TRUE; uac_open = 1; uac_run = 1; return RT_EOK; } int usbh_audio_close(struct usbh_audio *audio_class, const char *name) { struct urequest setup; rt_uint8_t intf = 0xff; int timeout = USB_TIMEOUT_BASIC; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->module[i].data_intf; } } if (intf == 0xff) { return -EIO; } LOG_D("Close audio module :%s\r\n", name); audio_class->is_opened = FALSE; setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_STANDARD | USB_REQ_TYPE_INTERFACE; setup.bRequest = USB_REQ_SET_INTERFACE; setup.wValue = 0; setup.wIndex = intf; setup.wLength = 0; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } uac_open = 0; uac_run = 0; return RT_EOK; } int usbh_audio_get_min_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *min_volume) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = GET_MIN; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } memcpy(min_volume, g_audio_buf, 2); return RT_EOK; } int usbh_audio_get_max_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *max_volume) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = GET_MAX; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } memcpy(max_volume, g_audio_buf, 2); return RT_EOK; } int usbh_audio_get_cur_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *cur_volume) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = GET_CUR; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } memcpy(cur_volume, g_audio_buf, 2); return RT_EOK; } int usbh_audio_get_res_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t *res_volume) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_IN | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = GET_RES; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } memcpy(res_volume, g_audio_buf, 2); return RT_EOK; } int usbh_audio_set_volume(struct usbh_audio *audio_class, const char *name, rt_uint16_t volume_hex) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; if(audio_class == RT_NULL) { return -EIO; } for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff || feature_id == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = SET_CUR; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; memcpy(g_audio_buf, &volume_hex, 2); if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } return RT_EOK; } int usbh_audio_set_volume_db(struct usbh_audio *audio_class, const char *name, int volume_db, int min_volume_db, int max_volume_db) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; rt_uint16_t volume_hex; float volume_min_db,volume_max_db; rt_uint8_t ch; int timeout = USB_TIMEOUT_BASIC; if(audio_class == RT_NULL) { return -EIO; } if ((volume_db > 127) || (volume_db < -127)) { return -EIO; } for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff || feature_id == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = SET_CUR; setup.wValue = (VOLUME_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 2; if (min_volume_db < 0x8000) { volume_min_db = (float)min_volume_db / 256; } else { volume_min_db = (float)(min_volume_db - 0x10000) / 256; } if (max_volume_db < 0x8000) { volume_max_db = (float)max_volume_db / 256; } else { volume_max_db = (float)(max_volume_db - 0x10000) / 256; } os_printf("Get ch: [%s] , dB range: %f dB ~ %f dB , set %d dB\r\n", name, volume_min_db, volume_max_db, volume_db); if (volume_db > volume_max_db || volume_db < volume_min_db) { os_printf("set (%d dB) not in range!!!\n",volume_db); return RT_ERROR; } if (volume_db >= 0) { volume_hex = volume_db * 256; if (volume_hex > max_volume_db) { os_printf("%s [ERR]volume_hex(%x) not in range\n",__FUNCTION__,volume_hex); return RT_ERROR; } } else { volume_hex = volume_db * 256 + 0x10000; if (volume_hex < min_volume_db) { os_printf("%s [ERR]volume_hex(%x) not in range\n",__FUNCTION__,volume_hex); return RT_ERROR; } } memcpy(g_audio_buf, &volume_hex, 2); if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 2, timeout) != 2) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } os_printf("%s success, volume_hex:%x\n",__FUNCTION__,volume_hex); return RT_EOK; } int usbh_audio_set_mute(struct usbh_audio *audio_class, const char *name, bool mute) { struct urequest setup; rt_uint8_t intf = 0xff; rt_uint8_t feature_id = 0xff; int timeout = USB_TIMEOUT_BASIC; rt_uint8_t ch; for (size_t i = 0; i < audio_class->module_num; i++) { if (strcmp(name, audio_class->module[i].name) == 0) { intf = audio_class->ctrl_intf; feature_id = audio_class->module[i].feature_unit_id; ch = audio_class->module[i].altsetting[AUDIO_SET_INTF_ALTSETTING].channels; } } if (intf == 0xff) { return -EIO; } setup.request_type = USB_REQ_TYPE_DIR_OUT | USB_REQ_TYPE_CLASS | USB_REQ_TYPE_INTERFACE; setup.bRequest = SET_CUR; setup.wValue = (MUTE_CONTROL << 8) | ch; setup.wIndex = (feature_id << 8) | intf; setup.wLength = 1; memcpy(g_audio_buf, &mute, 1); if(rt_usb_hcd_setup_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, &setup, timeout) != 8) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_out, g_audio_buf, 1, timeout) != 1) { return RT_ERROR; } if(rt_usb_hcd_pipe_xfer(audio_class->device->hcd, audio_class->device->pipe_ep0_in, RT_NULL, 0, timeout) != 0) { return RT_ERROR; } return RT_EOK; } void usbh_audio_list_module(struct usbh_audio *audio_class) { uep_desc_t ep_desc = RT_NULL; rt_uint8_t mult; rt_uint16_t mps; os_printf("============= Audio module information ===================\r\n"); os_printf("bcdADC :%04x\r\n", audio_class->bcdADC); os_printf("Num of modules :%u\r\n", audio_class->module_num); os_printf("Num of altsettings:%u\r\n", audio_class->num_of_intf_altsettings); for (rt_uint8_t i = 0; i < audio_class->module_num; i++) { os_printf(" module name :%s\r\n", audio_class->module[i].name); os_printf(" module feature unit id :%d\r\n", audio_class->module[i].feature_unit_id); if(strcmp("mic", audio_class->module[i].name) == 0) { ep_desc = &audio_class->isoin; }else if (strcmp("speaker", audio_class->module[i].name) == 0) { ep_desc = &audio_class->isoout; } mult = (ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_MASK) >> USB_MAXPACKETSIZE_ADDITIONAL_TRANSCATION_SHIFT; mps = ep_desc->wMaxPacketSize & USB_MAXPACKETSIZE_MASK; if (ep_desc->bEndpointAddress & 0x80) { audio_class->isoin_mps = mps * (mult + 1); } else { audio_class->isoout_mps = mps * (mult + 1); } os_printf(" Ep=%02X Attr=%02x Mps=%d Interval=%02u Mult=%02u\r\n", ep_desc->bEndpointAddress, ep_desc->bmAttributes, mps, ep_desc->bInterval, mult); for (rt_uint8_t j = 0; j < audio_class->num_of_intf_altsettings; j++) { if (j == 0) { os_printf(" Ingore altsetting 0\r\n"); continue; } os_printf(" Altsetting %u\r\n", j); os_printf(" module channels :%u\r\n", audio_class->module[i].altsetting[j].channels); //LOG_D(" module format_type :%u\r\n",audio_class->module[i].altsetting[j].format_type); os_printf(" module bitresolution :%u\r\n", audio_class->module[i].altsetting[j].bitresolution); os_printf(" module sampfreq num :%u\r\n", audio_class->module[i].altsetting[j].sampfreq_num); for (rt_uint8_t k = 0; k < audio_class->module[i].altsetting[j].sampfreq_num; k++) { os_printf(" module sampfreq :%d hz\r\n", audio_class->module[i].altsetting[j].sampfreq[k]); } } } os_printf("============= Audio module information ===================\r\n"); } static rt_err_t rt_usbh_class_driver_audio_enable(void *arg) { int ret; struct uhintf **p_intf = arg; rt_uint8_t intf; rt_uint8_t cur_iface = 0xff; rt_uint8_t cur_iface_count = 0xff; rt_uint8_t cur_alt_setting = 0xff; rt_uint8_t input_offset = 0; rt_uint8_t output_offset = 0; rt_uint8_t feature_unit_offset = 0; rt_uint8_t format_offset = 0; rt_uint8_t *p = RT_NULL; uhcd_t hcd = NULL; uep_desc_t ep_desc; if (p_intf[0] == NULL) { return -EIO; } hcd = p_intf[0]->device->hcd; intf = p_intf[0]->intf_desc->bInterfaceNumber; struct usbh_audio *audio_class = usbh_audio_class_alloc(); if (audio_class == RT_NULL) { LOG_D("Fail to alloc audio_class\r\n"); return RET_ERR; } audio_class->device = p_intf[0]->device; audio_class->ctrl_intf = intf; audio_class->num_of_intf_altsettings = 2; p_intf[0]->user_data = audio_class; p = (rt_uint8_t *)(p_intf[0]->device->cfg_desc); while (p[DESC_bLength]) { switch (p[DESC_bDescriptorType]) { case USB_DESC_TYPE_IAD: cur_iface_count = p[3]; break; case USB_DESC_TYPE_INTERFACE: cur_iface = p[INTF_DESC_bInterfaceNumber]; cur_alt_setting = p[INTF_DESC_bAlternateSetting]; break; case USB_DESC_TYPE_ENDPOINT: //os_printf("USB_DESC_TYPE_ENDPOINT\n"); if(((cur_iface == audio_class->module[0].data_intf) && (audio_class->module[0].data_intf != 0)) || ((cur_iface == audio_class->module[1].data_intf) && (audio_class->module[1].data_intf != 0))) { ep_desc = (struct uendpoint_descriptor *)p; os_printf("Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u Cur_iface:%d\r\n", cur_alt_setting, ep_desc->bEndpointAddress, ep_desc->bmAttributes, ep_desc->wMaxPacketSize, ep_desc->bInterval, cur_iface); if (cur_alt_setting == AUDIO_SET_INTF_ALTSETTING) { if(((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN ) && ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_ISOC)) { audio_class->isoin = *ep_desc; } if(((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_OUT ) && ((ep_desc->bmAttributes & USB_EP_ATTR_TYPE_MASK) == USB_EP_ATTR_ISOC)) { audio_class->isoout = *ep_desc; } } } break; case UDESC_CS_INTERFACE: if (cur_iface == audio_class->ctrl_intf) { switch (p[DESC_bDescriptorSubType]) { case UDESCSUB_AC_HEADER: { struct usb_audio_control_descriptor *desc = (struct usb_audio_control_descriptor *)p; audio_class->bcdADC = desc->bcdADC; audio_class->bInCollection = desc->bInCollection; } break; case UDESCSUB_AC_INPUT: { struct usb_audio_input_terminal *desc = (struct usb_audio_input_terminal *)p; audio_class->module[input_offset].input_terminal_id = desc->bTerminalId; audio_class->module[input_offset].input_terminal_type = desc->wTerminalType; audio_class->module[input_offset].input_channel_config = desc->wChannelConfig; if (desc->wTerminalType == UAT_STREAM) { audio_class->module[input_offset].terminal_link_id = desc->bTerminalId; } if (desc->wTerminalType == UATI_MICROPHONE) { audio_class->module[input_offset].name = "mic"; } input_offset++; } break; break; case UDESCSUB_AC_OUTPUT: { struct usb_audio_output_terminal *desc = (struct usb_audio_output_terminal *)p; audio_class->module[output_offset].output_terminal_id = desc->bTerminalId; audio_class->module[output_offset].output_terminal_type = desc->wTerminalType; if (desc->wTerminalType == UAT_STREAM) { audio_class->module[output_offset].terminal_link_id = desc->bTerminalId; } if (desc->wTerminalType == UATO_SPEAKER) { audio_class->module[output_offset].name = "speaker"; } output_offset++; } break; case UDESCSUB_AC_FEATURE: { struct usb_audio_feature_unit *desc = (struct usb_audio_feature_unit *)p; audio_class->module[feature_unit_offset].feature_unit_id = desc->bUnitId; audio_class->module[feature_unit_offset].feature_unit_controlsize = desc->bControlSize; for (rt_uint8_t j = 0; j < desc->bControlSize; j++) { audio_class->module[feature_unit_offset].feature_unit_controls[j] = p[6 + j]; } feature_unit_offset++; } break; case UDESCSUB_AC_PROCESSING: break; default: break; } } else if ((cur_iface < (audio_class->ctrl_intf + cur_iface_count)) && (cur_iface > audio_class->ctrl_intf)) { switch (p[DESC_bDescriptorSubType]) { case AS_GENERAL: break; case FORMAT_TYPE: { struct usb_audio_streaming_type1_descriptor *desc = (struct usb_audio_streaming_type1_descriptor *)p; audio_class->module[format_offset].data_intf = cur_iface; audio_class->module[format_offset].altsetting[cur_alt_setting].channels = desc->bNrChannels; audio_class->module[format_offset].altsetting[cur_alt_setting].format_type = desc->bFormatType; audio_class->module[format_offset].altsetting[cur_alt_setting].bitresolution = desc->bBitResolution; audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq_num = desc->bSamFreqType; for (rt_uint8_t j = 0; j < desc->bSamFreqType; j++) { audio_class->module[format_offset].altsetting[cur_alt_setting].sampfreq[j] = (rt_uint32_t)(p[10 + j * 3] << 16) | (rt_uint32_t)(p[9 + j * 3] << 8) | (rt_uint32_t)(p[8 + j * 3] << 0); } if (cur_alt_setting == (audio_class->num_of_intf_altsettings - 1)) { format_offset++; } } break; default: break; } } break; default: break; } /* skip to next descriptor */ p += p[DESC_bLength]; } if ((input_offset != output_offset) && (input_offset != feature_unit_offset) && (input_offset != format_offset)) { return -EIO; } audio_class->module_num = input_offset; usbh_audio_list_module(audio_class); audio_class->rx_buff = (rt_uint8_t *)rt_malloc(AUDIO_RX_PACKET_SIZE + USB_RX_BUFF_RESERVE_SIZE); if(audio_class->rx_buff == RT_NULL) { os_printf("malloc rx_buff fail\n"); return RT_ENOMEM; } for (size_t i = 0; i < audio_class->module_num; i++) { ret = usbh_audio_close(audio_class, audio_class->module[i].name); if (ret < 0) { os_printf("Fail to close audio module :%s\r\n", audio_class->module[i].name); return ret; } } snprintf(audio_class->devname, CONFIG_USBHOST_DEV_NAMELEN, DEV_FORMAT, audio_class->minor); os_printf("Register Audio Class:%s\r\n", audio_class->devname); usbh_audio_run(audio_class); return 0; } static rt_err_t rt_usbh_class_driver_audio_disable(void *arg) { int ret = RT_EOK; struct uhintf *p_intf = arg; if (p_intf == NULL) { return -EIO; } struct usbh_audio *audio_class = (struct usbh_audio *)p_intf->user_data; if (audio_class) { if (audio_class->devname[0] != '\0') { os_printf("Unregister Audio Class:%s\r\n", audio_class->devname); usbh_audio_stop(audio_class); } if(audio_class->rx_buff) { rt_free(audio_class->rx_buff); } usbh_audio_class_free(audio_class); } return ret; } /* ----------------------------- USB 2.0 / USB 1.1 UAC IRQ ----------------------------- */ static void _usbh_audio_spk_tx(void * p_dev, uint8_t ep, uint8_t *data, uint32_t len) { struct usb_device_dma_cfg dma_cfg; if (p_dev == RT_NULL || data == RT_NULL || len == 0) { return; } dma_cfg.ep_index = ep; dma_cfg.ep_dir = USB_CORE_HOST_EP_TX; dma_cfg.dma_addr = (rt_uint32_t *)data; dma_cfg.dma_len = len; usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL); } bool rtt_uac_data_deal(void *p_dev, rt_uint8_t ep) { rt_int32_t rx_len = 0; usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_GET_RX_DMA_LEN, ep, (rt_uint32_t)&rx_len); if((rx_len == 0) || (rx_len != AUDIO_RX_PACKET_SIZE)){ return 1; } if(rx_len < 0){ os_printf("The length of the configured dma needs to be increased\n"); return 1; } usbmic_packet_len = rx_len; // os_printf("rx_len:%d\n", rx_len); return 0; } void rtt_usbh_audio_irq(void * dev, rt_uint32_t irq, rt_uint8_t ep) { rt_uint32_t ret; struct usb_device *p_dev = (struct usb_device *)dev; struct usb_device_dma_cfg dma_cfg; if (!p_dev) return; switch (irq) { case USB_EP_RX_IRQ: if ((ep == (&g_audio_class[0])->pipe_in->pipe_index) && ((&g_audio_class[0])->pipe_in != RT_NULL)) { #if AUDIO_MIC_EN usb_dma_uac_irq_times++; if(uac_open && uac_run) { ret = rtt_uac_data_deal(p_dev, ep); if(ret == 0){ ret = usbmic_deal((struct usb_device *)p_dev, (uint8_t *)(&g_audio_class[0])->rx_buff); } dma_cfg.ep_index = ep; dma_cfg.ep_dir = USB_CORE_HOST_EP_RX; dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff; dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE; usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL); } #endif } break; case USB_EP_TX_IRQ: if ((ep == (&g_audio_class[0])->pipe_out->pipe_index) && ((&g_audio_class[0])->pipe_out != RT_NULL)) { #if AUDIO_SPK_EN usb_dma_uac_irq_times++; if(uac_open && uac_run) { usbspk_tx((struct usb_device *)p_dev, ep, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx); } #endif } break; default: break; } } rt_uint32_t rtt_usbh_audio_dev_pipe_mange(rt_uint8_t dev_num, const char *name, rt_uint8_t alloc_or_free) { uep_desc_t ep_desc = RT_NULL; upipe_t pipe; struct usbh_audio *audio_class = RT_NULL; if(dev_num >= CONFIG_USBHOST_MAX_AUDIO_CLASS) { os_printf("Invalid dev_num %d!!!!!!!!\n",dev_num); return -RT_ERROR; } audio_class = &g_audio_class[dev_num]; if (strcmp(name, "mic") == 0) { ep_desc = &audio_class->isoin; } else if (strcmp(name, "speaker") == 0) { ep_desc = &audio_class->isoout; } os_printf("Audio Class dev%d: Altsetting:%u, Ep=%02x Attr=%02u Mps=%d Interval=%02u\r\n", dev_num, AUDIO_SET_INTF_ALTSETTING, ep_desc->bEndpointAddress, ep_desc->bmAttributes, ep_desc->wMaxPacketSize, ep_desc->bInterval); if(ep_desc->bEndpointAddress == 0 || ep_desc->bmAttributes == 0 || ep_desc->wMaxPacketSize == 0) { return -RT_ERROR; } if(alloc_or_free) { pipe = rt_usb_instance_find_pipe(audio_class->device, ep_desc->bEndpointAddress); if(pipe != RT_NULL) { os_printf("g_video_class[%d] pipe has been alloced!!!\n",dev_num); return -RT_ERROR; } if (rt_usb_hcd_alloc_pipe(audio_class->device->hcd, &pipe, audio_class->device, ep_desc) != RT_EOK) { rt_kprintf("alloc iso pipe failed\n"); return -RT_ERROR; } os_printf("alloc iso pipe ok %x\n",pipe); rt_usb_instance_add_pipe(audio_class->device, pipe); if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { audio_class->pipe_in = pipe; } else { audio_class->pipe_out = pipe; } struct usb_device *p_dev = NULL; switch(g_audio_class[0].device->hcd->devid) { case HG_USB11_HOST_CONTROLLER_DEVID: { os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID); if (p_dev) { os_printf("kick usb11\n"); }; /* USB Full Speed : 1 frame = 1 ms */ if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 1); } else { usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 1); } } break; case HG_USB_HOST_CONTROLLER_DEVID: { os_printf("HG_USB_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID); if (p_dev) { os_printf("kick usb20\n"); }; if (usb_device_ioctl(p_dev, USB_HOST_GET_BUS_SPEED, 0, 0)) { /* USB High Speed : 8 microframe = 1 ms */ if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 4); } else { usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 4); } } else { /* USB Full Speed : 1 frame = 1 ms */ if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { usb_device_ioctl(p_dev, USB_HOST_SET_RX_INTERVAL, pipe->pipe_index, 1); } else { usb_device_ioctl(p_dev, USB_HOST_SET_TX_INTERVAL, pipe->pipe_index, 1); } } } break; default: break; } } else { if ((ep_desc->bEndpointAddress & USB_DIR_MASK) == USB_DIR_IN) { if(audio_class->pipe_in != RT_NULL) { rt_list_remove(&audio_class->pipe_in->list); rt_usb_hcd_free_pipe(audio_class->device->hcd, audio_class->pipe_in); audio_class->pipe_in = RT_NULL; } else { os_printf("g_audio_class[%d] pipe_in is NULL, not free\n",dev_num); return -RT_ERROR; } } else { if(audio_class->pipe_out != RT_NULL) { rt_list_remove(&audio_class->pipe_out->list); rt_usb_hcd_free_pipe(audio_class->device->hcd, audio_class->pipe_out); audio_class->pipe_out = RT_NULL; } else { os_printf("g_audio_class[%d] pipe_out is NULL, not free\n",dev_num); return -RT_ERROR; } } } return RT_EOK; } /* 用户调用接口 */ rt_uint32_t rtt_usbh_audio_user_open() { rt_uint32_t ret; struct usbh_audio *audio_class = &g_audio_class[0]; struct usb_device *p_dev = NULL; switch(g_audio_class[0].device->hcd->devid) { case HG_USB11_HOST_CONTROLLER_DEVID: { os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID); if (p_dev) { os_printf("kick usb11\n"); }; } break; case HG_USB_HOST_CONTROLLER_DEVID: { os_printf("HG_USB_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID); if (p_dev) { os_printf("kick usb20\n"); }; } break; default: break; } #if AUDIO_VOLUME_CONTROL_EN rt_uint16_t min_volume,max_volume,res_volume,cur_volume; #if AUDIO_MIC_EN //设置设备非静音状态和音量大小 usbh_audio_set_mute(audio_class, "mic", 0); //获取设备最大最小音量,设置音量大小 usbh_audio_get_cur_volume(audio_class, "mic", &cur_volume); usbh_audio_get_min_volume(audio_class, "mic", &min_volume); usbh_audio_get_max_volume(audio_class, "mic", &max_volume); usbh_audio_get_res_volume(audio_class, "mic", &res_volume); os_printf("[mic] min volume:%x,max volume:%x cur_volume:%x res_volume:%x\n",min_volume,max_volume,cur_volume,res_volume); usbh_audio_set_volume(audio_class, "mic", max_volume); //默认设置最大音量 //usbh_audio_set_volume_db(audio_class, "mic", -127, min_volume, max_volume); //根据打印的可调dB范围设置 #endif #if AUDIO_SPK_EN //设置设备非静音状态 usbh_audio_set_mute(audio_class, "speaker", 0); //获取设备最大最小音量,设置音量大小 usbh_audio_get_cur_volume(audio_class, "speaker", &cur_volume); usbh_audio_get_min_volume(audio_class, "speaker", &min_volume); usbh_audio_get_max_volume(audio_class, "speaker", &max_volume); usbh_audio_get_res_volume(audio_class, "spekaer", &res_volume); os_printf("[speaker] min volume:%x,max volume:%x cur_volume:%x res_volume:%x\n",min_volume,max_volume,cur_volume,res_volume); usbh_audio_set_volume(audio_class, "speaker", max_volume); //默认设置最大音量 //usbh_audio_set_volume_db(audio_class, "speaker", -37, min_volume, max_volume); //根据打印的可调dB范围设置 #endif #endif //给设备分配pipe #if AUDIO_MIC_EN rtt_usbh_audio_dev_pipe_mange(0, "mic", AUDIO_ALLOC_PIPE); #endif #if AUDIO_SPK_EN rtt_usbh_audio_dev_pipe_mange(0, "speaker", AUDIO_ALLOC_PIPE); #endif //USB发送打开UAC数据流命令 #if AUDIO_MIC_EN ret = usbh_audio_open(audio_class, "mic", AUDIO_MIC_SAMPLING_FREQ); if(ret != 0){ printf("mic open fail\n"); return -RT_ERROR; } #endif #if AUDIO_SPK_EN ret = usbh_audio_open(audio_class, "speaker", AUDIO_SPK_SAMPLING_FREQ); if(ret != 0){ printf("speaker open fail\n"); return -RT_ERROR; } #endif //应用层数据流初始化 #if AUDIO_MIC_EN usbmic_room_init(); usbmic_enum_finish(&usb_dma_uac_irq_times); #endif #if AUDIO_SPK_EN usbspk_room_init(AUDIO_TX_PACKET_SIZE); usbspk_enum_finish(&usb_dma_uac_irq_times); #endif //使能端点收发,触发中断循环 #if AUDIO_MIC_EN struct usb_device_dma_cfg dma_cfg; dma_cfg.ep_index = (&g_audio_class[0])->pipe_in->pipe_index; dma_cfg.ep_dir = USB_CORE_HOST_EP_RX; dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff; dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE; usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL); #endif #if AUDIO_SPK_EN usbspk_tx(p_dev, (&g_audio_class[0])->pipe_out->pipe_index, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx); #endif return RET_OK; } rt_uint32_t rtt_usbh_audio_user_close() { struct usbh_audio *audio_class = &g_audio_class[0]; rtt_usbh_audio_user_stop(); #if AUDIO_MIC_EN rtt_usbh_audio_dev_pipe_mange(0, "mic", AUDIO_FREE_PIPE); #endif #if AUDIO_SPK_EN rtt_usbh_audio_dev_pipe_mange(0, "speaker", AUDIO_FREE_PIPE); #endif #if AUDIO_MIC_EN usbh_audio_close(audio_class, "mic"); #endif #if AUDIO_SPK_EN usbh_audio_close(audio_class, "speaker"); #endif return RT_EOK; } rt_uint32_t rtt_usbh_audio_user_stop() { struct usb_device *p_dev = NULL; uac_stop(); switch(g_audio_class[0].device->hcd->devid) { case HG_USB11_HOST_CONTROLLER_DEVID: { os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID); if (p_dev) { #if AUDIO_MIC_EN hgusb11_v0_host_ep_abort(p_dev, USB_CORE_HOST_EP_RX, (&g_audio_class[0])->pipe_in->pipe_index); #endif #if AUDIO_SPK_EN hgusb11_v0_host_ep_abort(p_dev, USB_CORE_HOST_EP_TX, (&g_audio_class[0])->pipe_out->pipe_index); #endif }; } break; case HG_USB_HOST_CONTROLLER_DEVID: { os_printf("HG_USB_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID); if (p_dev) { #if AUDIO_MIC_EN hgusb20_ep_rx_abort((struct hgusb20_dev *)p_dev, (&g_audio_class[0])->pipe_in->pipe_index); #endif #if AUDIO_SPK_EN hgusb20_ep_tx_abort((struct hgusb20_dev *)p_dev, (&g_audio_class[0])->pipe_out->pipe_index); #endif }; } break; default: break; } return RT_EOK; } rt_uint32_t rtt_usbh_audio_user_start() { struct usb_device *p_dev = NULL; switch(g_audio_class[0].device->hcd->devid) { case HG_USB11_HOST_CONTROLLER_DEVID: { os_printf("HG_USB11_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USB11HOST_DEVID); if (p_dev) { os_printf("kick usb11\n"); }; } break; case HG_USB_HOST_CONTROLLER_DEVID: { os_printf("HG_USB_HOST_CONTROLLER_DEVID\n"); p_dev = (struct usb_device *)dev_get(HG_USBDEV_DEVID); if (p_dev) { os_printf("kick usb20\n"); }; } break; default: break; } if(uac_open) { uac_run = 1; #if AUDIO_MIC_EN struct usb_device_dma_cfg dma_cfg; dma_cfg.ep_index = (&g_audio_class[0])->pipe_in->pipe_index; dma_cfg.ep_dir = USB_CORE_HOST_EP_RX; dma_cfg.dma_addr = (rt_uint32_t *)g_audio_class[0].rx_buff; dma_cfg.dma_len = AUDIO_RX_PACKET_SIZE; usb_device_ioctl((struct usb_device *)p_dev, USB_HOST_KICK_EP_DMA, (rt_uint32_t)&dma_cfg, (rt_uint32_t)RT_NULL); #endif #if AUDIO_SPK_EN usbspk_tx((struct usb_device *)p_dev, (&g_audio_class[0])->pipe_out->pipe_index, AUDIO_TX_PACKET_SIZE, _usbh_audio_spk_tx); #endif } return RT_EOK; } int32 demo_atcmd_usbh_audio(const char *cmd, char *argv[], uint32 argc) { if (*argv[0] == '1') { if (*argv[1] == '1') { rtt_usbh_audio_user_open(); } if (*argv[1] == '0') { rtt_usbh_audio_user_close(); } } else if (*argv[0] == '2') { if (*argv[1] == '1') { } if (*argv[1] == '0') { } } printf("OK/n"); return 0; } void usbh_audio_thread_entry(void *arg) { //struct usbh_audio *audio_class = arg; } __attribute__((weak)) void usbh_audio_run(struct usbh_audio *audio_class) { rtt_usbh_audio_user_open(); #if 0 rt_thread_t usbh_audio_thread; usbh_audio_thread = rt_thread_create("usbh_video_thread", usbh_audio_thread_entry, audio_class, 1024, OS_TASK_PRIORITY_NORMAL, 20); if(usbh_audio_thread != RT_NULL) rt_thread_startup(usbh_audio_thread); #endif } __attribute__((weak)) void usbh_audio_stop(struct usbh_audio *audio_class) { } ucd_t rt_usbh_class_driver_audio(void) { usbh_audio_class.class_code = USB_CLASS_AUDIO; usbh_audio_class.enable = rt_usbh_class_driver_audio_enable; usbh_audio_class.disable = rt_usbh_class_driver_audio_disable; return &usbh_audio_class; } #endif