1 /*
2  * Copyright (c) 2006-2023, RT-Thread Development Team
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  *
6  * Change Logs:
7  * Date           Author       Notes
8  * 2019-09-07     flybreak     the first version
9  */
10 
11 #include <rthw.h>
12 #include <rtdevice.h>
13 #include "drivers/usb_device.h"
14 
15 #include "uaudioreg.h"
16 
17 #define DBG_TAG              "usbd.audio.mic"
18 #define DBG_LVL              DBG_INFO
19 #include <rtdbg.h>
20 
21 #define RECORD_SAMPLERATE   16000
22 #define RECORD_CHANNEL      1
23 #define RESOLUTION_BITS     16
24 
25 #define RESOLUTION_BYTE     (RESOLUTION_BITS / 8)
26 #define RECORD_PER_MS_SZ    ((RECORD_SAMPLERATE * RECORD_CHANNEL * RESOLUTION_BYTE) / 1000)
27 #define RECORD_BUFFER_SZ    (RECORD_PER_MS_SZ * 20)  /* 20ms */
28 
29 #if defined(RT_USBD_MIC_DEVICE_NAME)
30     #define MIC_DEVICE_NAME    RT_USBD_MIC_DEVICE_NAME
31 #else
32     #define MIC_DEVICE_NAME    "mic0"
33 #endif
34 
35 #define EVENT_RECORD_START   (1 << 0)
36 #define EVENT_RECORD_STOP    (1 << 1)
37 #define EVENT_RECORD_DATA    (1 << 2)
38 
39 #define MIC_INTF_STR_INDEX 8
40 /*
41  * uac mic descriptor define
42  */
43 
44 #define UAC_CS_INTERFACE            0x24
45 #define UAC_CS_ENDPOINT             0x25
46 
47 #define UAC_MAX_PACKET_SIZE         64
48 #define UAC_EP_MAX_PACKET_SIZE      32
49 #define UAC_CHANNEL_NUM             RECORD_CHANNEL
50 
51 struct uac_ac_descriptor
52 {
53 #ifdef RT_USB_DEVICE_COMPOSITE
54     struct uiad_descriptor iad_desc;
55 #endif
56     struct uinterface_descriptor intf_desc;
57     struct usb_audio_control_descriptor hdr_desc;
58     struct usb_audio_input_terminal it_desc;
59     struct usb_audio_output_terminal ot_desc;
60 #if UAC_USE_FEATURE_UNIT
61     struct usb_audio_feature_unit feature_unit_desc;
62 #endif
63 };
64 
65 struct uac_as_descriptor
66 {
67     struct uinterface_descriptor intf_desc;
68     struct usb_audio_streaming_interface_descriptor hdr_desc;
69     struct usb_audio_streaming_type1_descriptor format_type_desc;
70     struct uendpoint_descriptor ep_desc;
71     struct usb_audio_streaming_endpoint_descriptor as_ep_desc;
72 };
73 
74 /*
75  * uac mic device type
76  */
77 
78 struct uac_audio_mic
79 {
80     rt_device_t  dev;
81     rt_event_t   event;
82     rt_uint8_t   open_count;
83 
84     rt_uint8_t  *buffer;
85     rt_uint32_t  buffer_index;
86 
87     uep_t        ep;
88 };
89 static struct uac_audio_mic mic;
90 
91 rt_align(4)
92 static struct udevice_descriptor dev_desc =
93 {
94     USB_DESC_LENGTH_DEVICE,     //bLength;
95     USB_DESC_TYPE_DEVICE,       //type;
96     USB_BCD_VERSION,            //bcdUSB;
97     USB_CLASS_DEVICE,           //bDeviceClass;
98     0x00,                       //bDeviceSubClass;
99     0x00,                       //bDeviceProtocol;
100     UAC_MAX_PACKET_SIZE,        //bMaxPacketSize0;
101     _VENDOR_ID,                 //idVendor;
102     _PRODUCT_ID,                //idProduct;
103     USB_BCD_DEVICE,             //bcdDevice;
104     USB_STRING_MANU_INDEX,      //iManufacturer;
105     USB_STRING_PRODUCT_INDEX,   //iProduct;
106     USB_STRING_SERIAL_INDEX,    //iSerialNumber;Unused.
107     USB_DYNAMIC,                //bNumConfigurations;
108 };
109 
110 //FS and HS needed
111 rt_align(4)
112 static struct usb_qualifier_descriptor dev_qualifier =
113 {
114     sizeof(dev_qualifier),          //bLength
115     USB_DESC_TYPE_DEVICEQUALIFIER,  //bDescriptorType
116     0x0200,                         //bcdUSB
117     USB_CLASS_AUDIO,                //bDeviceClass
118     0x00,                           //bDeviceSubClass
119     0x00,                           //bDeviceProtocol
120     64,                             //bMaxPacketSize0
121     0x01,                           //bNumConfigurations
122     0,
123 };
124 
125 rt_align(4)
126 const static char *_ustring[] =
127 {
128     "Language",
129     "RT-Thread Team.",
130     "RT-Thread Audio Microphone",
131     "32021919830108",
132     "Configuration",
133     "Interface",
134 };
135 
136 rt_align(4)
137 static struct uac_ac_descriptor ac_desc =
138 {
139 #ifdef RT_USB_DEVICE_COMPOSITE
140     /* Interface Association Descriptor */
141     {
142         USB_DESC_LENGTH_IAD,
143         USB_DESC_TYPE_IAD,
144         USB_DYNAMIC,
145         0x02,
146         USB_CLASS_AUDIO,
147         USB_SUBCLASS_AUDIOSTREAMING,
148         0x00,
149         0x00,
150     },
151 #endif
152     /* Interface Descriptor */
153     {
154         USB_DESC_LENGTH_INTERFACE,
155         USB_DESC_TYPE_INTERFACE,
156         USB_DYNAMIC,
157         0x00,
158         0x00,
159         USB_CLASS_AUDIO,
160         USB_SUBCLASS_AUDIOCONTROL,
161         0x00,
162 #ifdef RT_USB_DEVICE_COMPOSITE
163         MIC_INTF_STR_INDEX,
164 #else
165         0x00,
166 #endif
167     },
168     /* Header Descriptor */
169     {
170         sizeof(struct usb_audio_control_descriptor),
171         UAC_CS_INTERFACE,
172         UDESCSUB_AC_HEADER,
173         0x0100,    /* Version: 1.00 */
174         0x001E,    /* Total length: 30 */
175         0x01,      /* Total number of interfaces: 1 */
176         {0x01},    /* Interface number: 1 */
177     },
178     /*  Input Terminal Descriptor */
179     {
180         sizeof(struct usb_audio_input_terminal),
181         UAC_CS_INTERFACE,
182         UDESCSUB_AC_INPUT,
183         0x01,      /* Terminal ID: 1 */
184         0x0201,    /* Terminal Type: Microphone (0x0201) */
185         0x00,      /* Assoc Terminal: 0 */
186         0x01,      /* Number Channels: 1 */
187         0x0000,    /* Channel Config: 0x0000 */
188         0x00,      /* Channel Names: 0 */
189         0x00,      /* Terminal: 0 */
190     },
191     /*  Output Terminal Descriptor */
192     {
193         sizeof(struct usb_audio_output_terminal),
194         UAC_CS_INTERFACE,
195         UDESCSUB_AC_OUTPUT,
196         0x02,      /* Terminal ID: 2 */
197         0x0101,    /* Terminal Type: USB Streaming (0x0101) */
198         0x00,      /* Assoc Terminal: 0 */
199         0x01,      /* Source ID: 1 */
200         0x00,      /* Terminal: 0 */
201     },
202 #if UAC_USE_FEATURE_UNIT
203     /*  Feature unit Descriptor */
204     {
205         sizeof(struct usb_audio_feature_unit),
206         UAC_CS_INTERFACE,
207         UDESCSUB_AC_FEATURE,
208         0x02,
209         0x01,
210         0x01,
211         0x00,
212         0x01,
213     },
214 #endif
215 };
216 
217 rt_align(4)
218 static struct uinterface_descriptor as_desc0 =
219 {
220     USB_DESC_LENGTH_INTERFACE,
221     USB_DESC_TYPE_INTERFACE,
222     USB_DYNAMIC,
223     0x00,
224     0x00,
225     USB_CLASS_AUDIO,
226     USB_SUBCLASS_AUDIOSTREAMING,
227     0x00,
228     0x00,
229 };
230 
231 rt_align(4)
232 static struct uac_as_descriptor as_desc =
233 {
234     /* Interface Descriptor */
235     {
236         USB_DESC_LENGTH_INTERFACE,
237         USB_DESC_TYPE_INTERFACE,
238         USB_DYNAMIC,
239         0x01,
240         0x01,
241         USB_CLASS_AUDIO,
242         USB_SUBCLASS_AUDIOSTREAMING,
243         0x00,
244         0x00,
245     },
246     /* General AS Descriptor */
247     {
248         sizeof(struct usb_audio_streaming_interface_descriptor),
249         UAC_CS_INTERFACE,
250         AS_GENERAL,
251         0x02,      /* Terminal ID: 2 */
252         0x01,      /* Interface delay in frames: 1 */
253         UA_FMT_PCM,
254     },
255     /* Format type i Descriptor */
256     {
257         sizeof(struct usb_audio_streaming_type1_descriptor),
258         UAC_CS_INTERFACE,
259         FORMAT_TYPE,
260         FORMAT_TYPE_I,
261         UAC_CHANNEL_NUM,
262         2,         /* Subframe Size: 2 */
263         RESOLUTION_BITS,
264         0x01,      /* Samples Frequence Type: 1 */
265         {0},       /* Samples Frequence */
266     },
267     /* Endpoint Descriptor */
268     {
269         USB_DESC_LENGTH_ENDPOINT,
270         USB_DESC_TYPE_ENDPOINT,
271         USB_DYNAMIC | USB_DIR_IN,
272         USB_EP_ATTR_ISOC,
273         UAC_EP_MAX_PACKET_SIZE,
274         0x01,
275     },
276     /* AS Endpoint Descriptor */
277     {
278         sizeof(struct usb_audio_streaming_endpoint_descriptor),
279         UAC_CS_ENDPOINT,
280         AS_GENERAL,
281     },
282 };
283 
mic_entry(void * parameter)284 void mic_entry(void *parameter)
285 {
286     struct rt_audio_caps caps = {0};
287     rt_uint32_t e, index;
288 
289     mic.buffer = rt_malloc(RECORD_BUFFER_SZ);
290     if (mic.buffer == RT_NULL)
291     {
292         LOG_E("malloc failed");
293         goto __exit;
294     }
295 
296     mic.dev = rt_device_find(MIC_DEVICE_NAME);
297     if (mic.dev == RT_NULL)
298     {
299         LOG_E("can't find device:%s", MIC_DEVICE_NAME);
300         goto __exit;
301     }
302 
303     while (1)
304     {
305         if (rt_event_recv(mic.event, EVENT_RECORD_START | EVENT_RECORD_STOP,
306                           RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
307                           1000, &e) != RT_EOK)
308         {
309             continue;
310         }
311         if (mic.open_count == 0)
312         {
313             continue;
314         }
315         LOG_D("record start");
316 
317         rt_device_open(mic.dev, RT_DEVICE_OFLAG_RDONLY);
318 
319         caps.main_type               = AUDIO_TYPE_INPUT;
320         caps.sub_type                = AUDIO_DSP_PARAM;
321         caps.udata.config.samplerate = RECORD_SAMPLERATE;
322         caps.udata.config.channels   = RECORD_CHANNEL;
323         caps.udata.config.samplebits = RESOLUTION_BITS;
324         rt_device_control(mic.dev, AUDIO_CTL_CONFIGURE, &caps);
325 
326         while (1)
327         {
328             if (rt_event_recv(mic.event, EVENT_RECORD_DATA | EVENT_RECORD_STOP,
329                               RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR,
330                               1000, &e) != RT_EOK)
331             {
332                 if (mic.open_count > 0)
333                     continue;
334                 else
335                     break;
336             }
337             if (e & EVENT_RECORD_DATA)
338             {
339                 index = (mic.buffer_index >= RECORD_BUFFER_SZ / 2) ? 0 : (RECORD_BUFFER_SZ / 2);
340                 rt_device_read(mic.dev, 0, mic.buffer + index, RECORD_BUFFER_SZ / 2);
341             }
342             else if (e & EVENT_RECORD_STOP)
343             {
344                 break;
345             }
346         }
347         LOG_D("record stop");
348         rt_device_close(mic.dev);
349     }
350 
351 __exit:
352     if (mic.buffer)
353         rt_free(mic.buffer);
354 }
355 
_record_start(ufunction_t func)356 static rt_err_t _record_start(ufunction_t func)
357 {
358     mic.ep->request.buffer = RT_NULL;
359     mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
360     mic.ep->request.req_type = UIO_REQUEST_WRITE;
361     rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
362 
363     mic.open_count ++;
364     rt_event_send(mic.event, EVENT_RECORD_START);
365     return 0;
366 }
367 
_record_stop(ufunction_t func)368 static rt_err_t _record_stop(ufunction_t func)
369 {
370     mic.open_count --;
371     rt_event_send(mic.event, EVENT_RECORD_STOP);
372     return 0;
373 }
374 
_ep_data_in_handler(ufunction_t func,rt_size_t size)375 static rt_err_t _ep_data_in_handler(ufunction_t func, rt_size_t size)
376 {
377     RT_ASSERT(func != RT_NULL);
378     LOG_D("_ep_data_in_handler");
379 
380     mic.ep->request.buffer = mic.buffer + mic.buffer_index;
381     mic.ep->request.size = UAC_EP_MAX_PACKET_SIZE;
382     mic.ep->request.req_type = UIO_REQUEST_WRITE;
383     rt_usbd_io_request(func->device, mic.ep, &mic.ep->request);
384 
385     mic.buffer_index += UAC_EP_MAX_PACKET_SIZE;
386     if (mic.buffer_index >= RECORD_BUFFER_SZ)
387     {
388         mic.buffer_index = 0;
389         rt_event_send(mic.event, EVENT_RECORD_DATA);
390     }
391     else if (mic.buffer_index == RECORD_BUFFER_SZ / 2)
392     {
393         rt_event_send(mic.event, EVENT_RECORD_DATA);
394     }
395 
396     return RT_EOK;
397 }
398 
_interface_as_handler(ufunction_t func,ureq_t setup)399 static rt_err_t _interface_as_handler(ufunction_t func, ureq_t setup)
400 {
401     RT_ASSERT(func != RT_NULL);
402     RT_ASSERT(func->device != RT_NULL);
403     RT_ASSERT(setup != RT_NULL);
404 
405     LOG_D("_interface_as_handler");
406 
407     if ((setup->request_type & USB_REQ_TYPE_MASK) == USB_REQ_TYPE_STANDARD)
408     {
409         switch (setup->bRequest)
410         {
411         case USB_REQ_GET_INTERFACE:
412             break;
413         case USB_REQ_SET_INTERFACE:
414             LOG_D("set interface handler");
415             if (setup->wValue == 1)
416             {
417                 _record_start(func);
418             }
419             else if (setup->wValue == 0)
420             {
421                 _record_stop(func);
422             }
423             break;
424         default:
425             LOG_D("unknown uac request 0x%x", setup->bRequest);
426             return -RT_ERROR;
427         }
428     }
429 
430     return RT_EOK;
431 }
432 
_function_enable(ufunction_t func)433 static rt_err_t _function_enable(ufunction_t func)
434 {
435     RT_ASSERT(func != RT_NULL);
436 
437     LOG_D("uac function enable");
438 
439     return RT_EOK;
440 }
441 
_function_disable(ufunction_t func)442 static rt_err_t _function_disable(ufunction_t func)
443 {
444     RT_ASSERT(func != RT_NULL);
445 
446     LOG_D("uac function disable");
447     _record_stop(func);
448     return RT_EOK;
449 }
450 
451 static struct ufunction_ops ops =
452 {
453     _function_enable,
454     _function_disable,
455     RT_NULL,
456 };
457 /**
458  * This function will configure uac descriptor.
459  *
460  * @param comm the communication interface number.
461  * @param data the data interface number.
462  *
463  * @return RT_EOK on successful.
464  */
_uac_descriptor_config(struct uac_ac_descriptor * ac,rt_uint8_t cintf_nr,struct uac_as_descriptor * as,rt_uint8_t sintf_nr)465 static rt_err_t _uac_descriptor_config(struct uac_ac_descriptor *ac,
466                                        rt_uint8_t cintf_nr, struct uac_as_descriptor *as, rt_uint8_t sintf_nr)
467 {
468     ac->hdr_desc.baInterfaceNr[0] = sintf_nr;
469 #ifdef RT_USB_DEVICE_COMPOSITE
470     ac->iad_desc.bFirstInterface = cintf_nr;
471 #endif
472 
473     return RT_EOK;
474 }
475 
_uac_samplerate_config(struct uac_as_descriptor * as,rt_uint32_t samplerate)476 static rt_err_t _uac_samplerate_config(struct uac_as_descriptor *as, rt_uint32_t samplerate)
477 {
478     as->format_type_desc.tSamFreq[0 * 3 + 2] = samplerate >> 16 & 0xff;
479     as->format_type_desc.tSamFreq[0 * 3 + 1] = samplerate >> 8 & 0xff;
480     as->format_type_desc.tSamFreq[0 * 3 + 0] = samplerate & 0xff;
481     return RT_EOK;
482 }
483 
484 /**
485  * This function will create a uac function instance.
486  *
487  * @param device the usb device object.
488  *
489  * @return RT_EOK on successful.
490  */
rt_usbd_function_uac_mic_create(udevice_t device)491 ufunction_t rt_usbd_function_uac_mic_create(udevice_t device)
492 {
493     ufunction_t func;
494     uintf_t intf_ac, intf_as;
495     ualtsetting_t setting_as0;
496     ualtsetting_t setting_ac, setting_as;
497     struct uac_as_descriptor *as_desc_t;
498 
499     /* parameter check */
500     RT_ASSERT(device != RT_NULL);
501 
502 #ifdef RT_USB_DEVICE_COMPOSITE
503     rt_usbd_device_set_interface_string(device, MIC_INTF_STR_INDEX, _ustring[2]);
504 #else
505     /* set usb device string description */
506     rt_usbd_device_set_string(device, _ustring);
507 #endif
508     /* create a uac function */
509     func = rt_usbd_function_new(device, &dev_desc, &ops);
510     //not support HS
511     //rt_usbd_device_set_qualifier(device, &dev_qualifier);
512 
513     /* create interface */
514     intf_ac = rt_usbd_interface_new(device, RT_NULL);
515     intf_as = rt_usbd_interface_new(device, _interface_as_handler);
516 
517     /* create alternate setting */
518     setting_ac = rt_usbd_altsetting_new(sizeof(struct uac_ac_descriptor));
519     setting_as0 = rt_usbd_altsetting_new(sizeof(struct uinterface_descriptor));
520     setting_as = rt_usbd_altsetting_new(sizeof(struct uac_as_descriptor));
521     /* config desc in alternate setting */
522     rt_usbd_altsetting_config_descriptor(setting_ac, &ac_desc,
523                                          (rt_off_t) & ((struct uac_ac_descriptor *)0)->intf_desc);
524     rt_usbd_altsetting_config_descriptor(setting_as0, &as_desc0, 0);
525     rt_usbd_altsetting_config_descriptor(setting_as, &as_desc,
526                                          (rt_off_t) & ((struct uac_as_descriptor *)0)->intf_desc);
527     /* configure the uac interface descriptor */
528     _uac_descriptor_config(setting_ac->desc, intf_ac->intf_num, setting_as->desc, intf_as->intf_num);
529     _uac_samplerate_config(setting_as->desc, RECORD_SAMPLERATE);
530 
531     /* create endpoint */
532     as_desc_t = (struct uac_as_descriptor *)setting_as->desc;
533     mic.ep = rt_usbd_endpoint_new(&as_desc_t->ep_desc, _ep_data_in_handler);
534 
535     /* add the endpoint to the alternate setting */
536     rt_usbd_altsetting_add_endpoint(setting_as, mic.ep);
537 
538     /* add the alternate setting to the interface, then set default setting of the interface */
539     rt_usbd_interface_add_altsetting(intf_ac, setting_ac);
540     rt_usbd_set_altsetting(intf_ac, 0);
541     rt_usbd_interface_add_altsetting(intf_as, setting_as0);
542     rt_usbd_interface_add_altsetting(intf_as, setting_as);
543     rt_usbd_set_altsetting(intf_as, 0);
544 
545     /* add the interface to the uac function */
546     rt_usbd_function_add_interface(func, intf_ac);
547     rt_usbd_function_add_interface(func, intf_as);
548 
549     return func;
550 }
551 
audio_mic_init(void)552 int audio_mic_init(void)
553 {
554     rt_thread_t mic_tid;
555     mic.event = rt_event_create("mic_event", RT_IPC_FLAG_FIFO);
556 
557     mic_tid = rt_thread_create("mic_thread",
558                                mic_entry, RT_NULL,
559                                1024,
560                                5, 10);
561 
562     if (mic_tid != RT_NULL)
563         rt_thread_startup(mic_tid);
564     return RT_EOK;
565 }
566 INIT_COMPONENT_EXPORT(audio_mic_init);
567 
568 /*
569  *  register uac class
570  */
571 struct udclass uac_class =
572 {
573     .rt_usbd_function_create = rt_usbd_function_uac_mic_create
574 };
575 
rt_usbd_uac_mic_class_register(void)576 int rt_usbd_uac_mic_class_register(void)
577 {
578     rt_usbd_class_register(&uac_class);
579     return 0;
580 }
581 INIT_PREV_EXPORT(rt_usbd_uac_mic_class_register);
582