462 lines
11 KiB
C
462 lines
11 KiB
C
|
#include "app_config.h"
|
||
|
#include "system/includes.h"
|
||
|
#include "printf.h"
|
||
|
#include "usb/usb_config.h"
|
||
|
#include "usb/device/usb_stack.h"
|
||
|
|
||
|
#if TCFG_USB_SLAVE_AUDIO_ENABLE
|
||
|
#include "usb/device/uac_audio.h"
|
||
|
#include "uac_stream.h"
|
||
|
#include "audio_config.h"
|
||
|
|
||
|
#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
|
||
|
#include "audio_track.h"
|
||
|
#endif
|
||
|
|
||
|
|
||
|
#define LOG_TAG_CONST USB
|
||
|
#define LOG_TAG "[UAC]"
|
||
|
#define LOG_ERROR_ENABLE
|
||
|
#define LOG_DEBUG_ENABLE
|
||
|
#define LOG_INFO_ENABLE
|
||
|
/* #define LOG_DUMP_ENABLE */
|
||
|
#define LOG_CLI_ENABLE
|
||
|
#include "debug.h"
|
||
|
|
||
|
#define UAC_DEBUG_ECHO_MODE 0
|
||
|
|
||
|
static volatile u8 speaker_stream_is_open = 0;
|
||
|
struct uac_speaker_handle {
|
||
|
cbuffer_t cbuf;
|
||
|
volatile u8 need_resume;
|
||
|
u8 channel;
|
||
|
u8 alive;
|
||
|
void *buffer;
|
||
|
void *audio_track;
|
||
|
//void (*rx_handler)(int, void *, int);
|
||
|
};
|
||
|
|
||
|
static void (*uac_rx_handler)(int, void *, int) = NULL;
|
||
|
|
||
|
#if (SOUNDCARD_ENABLE)
|
||
|
#define UAC_BUFFER_SIZE (4 * 1024)
|
||
|
#else
|
||
|
#define UAC_BUFFER_SIZE (2 * 1024)
|
||
|
#endif
|
||
|
|
||
|
#define UAC_BUFFER_MAX (UAC_BUFFER_SIZE * 50 / 100)
|
||
|
|
||
|
static struct uac_speaker_handle *uac_speaker = NULL;
|
||
|
|
||
|
#if USB_MALLOC_ENABLE
|
||
|
#else
|
||
|
static struct uac_speaker_handle uac_speaker_handle SEC(.uac_var);
|
||
|
static u8 uac_rx_buffer[UAC_BUFFER_SIZE] ALIGNED(4) SEC(.uac_rx);
|
||
|
#endif
|
||
|
u32 uac_speaker_stream_length()
|
||
|
{
|
||
|
return UAC_BUFFER_SIZE;
|
||
|
}
|
||
|
u32 uac_speaker_stream_size()
|
||
|
{
|
||
|
if (!speaker_stream_is_open) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
if (uac_speaker) {
|
||
|
return cbuf_get_data_size(&uac_speaker->cbuf);
|
||
|
}
|
||
|
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
u32 uac_speaker_get_alive()
|
||
|
{
|
||
|
if (uac_speaker) {
|
||
|
return uac_speaker->alive;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
void uac_speaker_set_alive(u8 alive)
|
||
|
{
|
||
|
local_irq_disable();
|
||
|
if (uac_speaker) {
|
||
|
uac_speaker->alive = alive;
|
||
|
}
|
||
|
local_irq_enable();
|
||
|
}
|
||
|
|
||
|
void uac_speaker_stream_buf_clear(void)
|
||
|
{
|
||
|
if (speaker_stream_is_open) {
|
||
|
cbuf_clear(&uac_speaker->cbuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void set_uac_speaker_rx_handler(void *priv, void (*rx_handler)(int, void *, int))
|
||
|
{
|
||
|
uac_rx_handler = rx_handler;
|
||
|
/* if (uac_speaker) { */
|
||
|
/* uac_speaker->rx_handler = rx_handler; */
|
||
|
/* } */
|
||
|
}
|
||
|
|
||
|
int uac_speaker_stream_sample_rate(void)
|
||
|
{
|
||
|
#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
|
||
|
if (uac_speaker && uac_speaker->audio_track) {
|
||
|
int sr = audio_local_sample_track_rate(uac_speaker->audio_track);
|
||
|
if ((sr < (SPK_AUDIO_RATE + 500)) && (sr > (SPK_AUDIO_RATE - 500))) {
|
||
|
return sr;
|
||
|
}
|
||
|
/* printf("uac audio_track reset \n"); */
|
||
|
local_irq_disable();
|
||
|
audio_local_sample_track_close(uac_speaker->audio_track);
|
||
|
uac_speaker->audio_track = audio_local_sample_track_open(SPK_CHANNEL, SPK_AUDIO_RATE, 1000);
|
||
|
local_irq_enable();
|
||
|
}
|
||
|
#endif
|
||
|
return SPK_AUDIO_RATE;
|
||
|
}
|
||
|
|
||
|
void uac_speaker_stream_write(const u8 *obuf, u32 len)
|
||
|
{
|
||
|
if (speaker_stream_is_open) {
|
||
|
//write dac
|
||
|
#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
|
||
|
if (uac_speaker->audio_track) {
|
||
|
audio_local_sample_track_in_period(uac_speaker->audio_track, (len >> 1) / uac_speaker->channel);
|
||
|
}
|
||
|
#endif
|
||
|
int wlen = cbuf_write(&uac_speaker->cbuf, (void *)obuf, len);
|
||
|
if (wlen != len) {
|
||
|
//putchar('W');
|
||
|
}
|
||
|
//if (uac_speaker->rx_handler) {
|
||
|
if (uac_rx_handler) {
|
||
|
/* if (uac_speaker->cbuf.data_len >= UAC_BUFFER_MAX) { */
|
||
|
// 马上就要满了,赶紧取走
|
||
|
uac_speaker->need_resume = 1; //2020-12-22注:无需唤醒
|
||
|
/* } */
|
||
|
if (uac_speaker->need_resume) {
|
||
|
uac_speaker->need_resume = 0;
|
||
|
uac_rx_handler(0, (void *)obuf, len);
|
||
|
//uac_speaker->rx_handler(0, (void *)obuf, len);
|
||
|
}
|
||
|
}
|
||
|
uac_speaker->alive = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
int uac_speaker_read(void *priv, void *data, u32 len)
|
||
|
{
|
||
|
int r_len;
|
||
|
int err = 0;
|
||
|
|
||
|
local_irq_disable();
|
||
|
if (!speaker_stream_is_open) {
|
||
|
local_irq_enable();
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
r_len = cbuf_get_data_size(&uac_speaker->cbuf);
|
||
|
if (r_len) {
|
||
|
r_len = r_len > len ? len : r_len;
|
||
|
r_len = cbuf_read(&uac_speaker->cbuf, data, r_len);
|
||
|
if (!r_len) {
|
||
|
putchar('U');
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (r_len == 0) {
|
||
|
uac_speaker->need_resume = 1;
|
||
|
}
|
||
|
local_irq_enable();
|
||
|
return r_len;
|
||
|
}
|
||
|
|
||
|
void uac_speaker_stream_open(u32 samplerate, u32 ch)
|
||
|
{
|
||
|
if (speaker_stream_is_open) {
|
||
|
return;
|
||
|
}
|
||
|
log_info("%s", __func__);
|
||
|
|
||
|
if (!uac_speaker) {
|
||
|
#if USB_MALLOC_ENABLE
|
||
|
|
||
|
uac_speaker = zalloc(sizeof(struct uac_speaker_handle));
|
||
|
if (!uac_speaker) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
uac_speaker->buffer = malloc(UAC_BUFFER_SIZE);
|
||
|
if (!uac_speaker->buffer) {
|
||
|
free(uac_speaker);
|
||
|
uac_speaker = NULL;
|
||
|
goto __err;
|
||
|
}
|
||
|
|
||
|
|
||
|
#else
|
||
|
|
||
|
uac_speaker = &uac_speaker_handle;
|
||
|
|
||
|
memset(uac_speaker, 0, sizeof(struct uac_speaker_handle));
|
||
|
|
||
|
uac_speaker->buffer = uac_rx_buffer;
|
||
|
#endif
|
||
|
uac_speaker->channel = ch;
|
||
|
#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
|
||
|
uac_speaker->audio_track = audio_local_sample_track_open(ch, samplerate, 1000);
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
|
||
|
//uac_speaker->rx_handler = NULL;
|
||
|
|
||
|
cbuf_init(&uac_speaker->cbuf, uac_speaker->buffer, UAC_BUFFER_SIZE);
|
||
|
speaker_stream_is_open = 1;
|
||
|
struct sys_event event;
|
||
|
event.type = SYS_DEVICE_EVENT;
|
||
|
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||
|
event.u.dev.event = USB_AUDIO_PLAY_OPEN;
|
||
|
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||
|
|
||
|
#if !UAC_DEBUG_ECHO_MODE
|
||
|
sys_event_notify(&event);
|
||
|
#endif
|
||
|
|
||
|
return;
|
||
|
|
||
|
__err:
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
void uac_speaker_stream_close()
|
||
|
{
|
||
|
if (speaker_stream_is_open == 0) {
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
log_info("%s", __func__);
|
||
|
speaker_stream_is_open = 0;
|
||
|
|
||
|
if (uac_speaker) {
|
||
|
#ifdef CONFIG_MEDIA_DEVELOP_ENABLE
|
||
|
audio_local_sample_track_close(uac_speaker->audio_track);
|
||
|
#endif
|
||
|
uac_speaker->audio_track = NULL;
|
||
|
#if USB_MALLOC_ENABLE
|
||
|
if (uac_speaker->buffer) {
|
||
|
free(uac_speaker->buffer);
|
||
|
}
|
||
|
free(uac_speaker);
|
||
|
#endif
|
||
|
uac_speaker = NULL;
|
||
|
}
|
||
|
struct sys_event event;
|
||
|
event.type = SYS_DEVICE_EVENT;
|
||
|
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||
|
event.u.dev.event = USB_AUDIO_PLAY_CLOSE;
|
||
|
event.u.dev.value = (int)0;
|
||
|
|
||
|
sys_event_notify(&event);
|
||
|
}
|
||
|
|
||
|
int uac_get_spk_vol()
|
||
|
{
|
||
|
int max_vol = get_max_sys_vol();
|
||
|
int vol = app_audio_get_volume(APP_AUDIO_STATE_MUSIC);
|
||
|
if (vol * 100 / max_vol < 100) {
|
||
|
return vol * 100 / max_vol;
|
||
|
} else {
|
||
|
return 99;
|
||
|
}
|
||
|
return 0;
|
||
|
}
|
||
|
static u32 mic_stream_is_open;
|
||
|
void uac_mute_volume(u32 type, u32 l_vol, u32 r_vol)
|
||
|
{
|
||
|
struct sys_event event;
|
||
|
event.type = SYS_DEVICE_EVENT;
|
||
|
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||
|
|
||
|
static u32 last_spk_l_vol = (u32) - 1, last_spk_r_vol = (u32) - 1;
|
||
|
static u32 last_mic_vol = (u32) - 1;
|
||
|
|
||
|
switch (type) {
|
||
|
case MIC_FEATURE_UNIT_ID: //MIC
|
||
|
if (mic_stream_is_open == 0) {
|
||
|
return ;
|
||
|
}
|
||
|
if (l_vol == last_mic_vol) {
|
||
|
return;
|
||
|
}
|
||
|
last_mic_vol = l_vol;
|
||
|
event.u.dev.event = USB_AUDIO_SET_MIC_VOL;
|
||
|
break;
|
||
|
case SPK_FEATURE_UNIT_ID: //SPK
|
||
|
if (speaker_stream_is_open == 0) {
|
||
|
return;
|
||
|
}
|
||
|
if (l_vol == last_spk_l_vol && r_vol == last_spk_r_vol) {
|
||
|
return;
|
||
|
}
|
||
|
last_spk_l_vol = l_vol;
|
||
|
last_spk_r_vol = r_vol;
|
||
|
event.u.dev.event = USB_AUDIO_SET_PLAY_VOL;
|
||
|
break;
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
event.u.dev.value = (int)(r_vol << 16 | l_vol);
|
||
|
sys_event_notify(&event);
|
||
|
}
|
||
|
|
||
|
|
||
|
static int (*mic_tx_handler)(int, void *, int) = NULL;
|
||
|
int uac_mic_stream_read(u8 *buf, u32 len)
|
||
|
{
|
||
|
if (mic_stream_is_open == 0) {
|
||
|
return 0;
|
||
|
}
|
||
|
#if 0//48K 1ksin
|
||
|
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
|
||
|
};
|
||
|
u16 *l_ch = (u16 *)buf;
|
||
|
u16 *r_ch = (u16 *)buf;
|
||
|
r_ch++;
|
||
|
for (int i = 0; i < len / 2; i++) {
|
||
|
*l_ch = sin_48k[i];
|
||
|
*r_ch = sin_48k[i];
|
||
|
l_ch += 1;
|
||
|
r_ch += 1;
|
||
|
}
|
||
|
return len;
|
||
|
#elif UAC_DEBUG_ECHO_MODE
|
||
|
uac_speaker_read(NULL, buf, len);
|
||
|
#if MIC_CHANNEL == 2
|
||
|
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
|
||
|
};
|
||
|
u16 *r_ch = (u16 *)buf;
|
||
|
r_ch++;
|
||
|
for (int i = 0; i < len / 4; i++) {
|
||
|
*r_ch = sin_48k[i];
|
||
|
r_ch += 2;
|
||
|
}
|
||
|
#endif
|
||
|
return len;
|
||
|
#else
|
||
|
if (mic_tx_handler) {
|
||
|
#if 1
|
||
|
return mic_tx_handler(0, buf, len);
|
||
|
#else
|
||
|
//16bit ---> 24bit
|
||
|
int rlen = mic_tx_handler(0, tmp_buf, len / 3 * 2);
|
||
|
rlen /= 2; //sampe point
|
||
|
for (int i = 0 ; i < rlen ; i++) {
|
||
|
buf[i * 3] = 0;
|
||
|
buf[i * 3 + 1] = tmp_buf[i * 2];
|
||
|
buf[i * 3 + 2] = tmp_buf[i * 2 + 1];
|
||
|
}
|
||
|
#endif
|
||
|
} else {
|
||
|
putchar('N');
|
||
|
}
|
||
|
return 0;
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void set_uac_mic_tx_handler(void *priv, int (*tx_handler)(int, void *, int))
|
||
|
{
|
||
|
mic_tx_handler = tx_handler;
|
||
|
}
|
||
|
|
||
|
u32 uac_mic_stream_open(u32 samplerate, u32 frame_len, u32 ch)
|
||
|
{
|
||
|
if (mic_stream_is_open) {
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
/* mic_tx_handler = NULL; */
|
||
|
log_info("%s", __func__);
|
||
|
|
||
|
struct sys_event event;
|
||
|
event.type = SYS_DEVICE_EVENT;
|
||
|
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||
|
event.u.dev.event = USB_AUDIO_MIC_OPEN;
|
||
|
event.u.dev.value = (int)((ch << 24) | samplerate);
|
||
|
mic_stream_is_open = 1;
|
||
|
|
||
|
#if !UAC_DEBUG_ECHO_MODE
|
||
|
sys_event_notify(&event);
|
||
|
#endif
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void uac_mic_stream_close()
|
||
|
{
|
||
|
if (mic_stream_is_open == 0) {
|
||
|
return ;
|
||
|
}
|
||
|
log_info("%s", __func__);
|
||
|
struct sys_event event;
|
||
|
event.type = SYS_DEVICE_EVENT;
|
||
|
event.arg = (void *)DEVICE_EVENT_FROM_UAC;
|
||
|
event.u.dev.event = USB_AUDIO_MIC_CLOSE;
|
||
|
event.u.dev.value = (int)0;
|
||
|
mic_stream_is_open = 0;
|
||
|
sys_event_notify(&event);
|
||
|
}
|
||
|
|
||
|
_WEAK_
|
||
|
s8 app_audio_get_volume(u8 state)
|
||
|
{
|
||
|
return 88;
|
||
|
}
|
||
|
_WEAK_
|
||
|
void usb_audio_demo_exit(void)
|
||
|
{
|
||
|
|
||
|
}
|
||
|
_WEAK_
|
||
|
int usb_audio_demo_init(void)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
_WEAK_
|
||
|
u8 get_max_sys_vol(void)
|
||
|
{
|
||
|
return 100;
|
||
|
}
|
||
|
_WEAK_
|
||
|
void *audio_local_sample_track_open(u8 channel, int sample_rate, int period)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
_WEAK_
|
||
|
int audio_local_sample_track_in_period(void *c, int samples)
|
||
|
{
|
||
|
return 0;
|
||
|
}
|
||
|
_WEAK_
|
||
|
void audio_local_sample_track_close(void *c)
|
||
|
{
|
||
|
}
|
||
|
#endif
|