diff --git a/components/drivers/audio/SConscript b/components/drivers/audio/SConscript new file mode 100644 index 0000000000000000000000000000000000000000..2c5b626778e371448f2a4166ce7583cb5cb4613d --- /dev/null +++ b/components/drivers/audio/SConscript @@ -0,0 +1,9 @@ +from building import * + +cwd = GetCurrentDir() +src = Glob('*.c') +CPPPATH = [cwd] + +group = DefineGroup('cJSON', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH) + +Return('group') diff --git a/components/drivers/audio/audio.c b/components/drivers/audio/audio.c new file mode 100644 index 0000000000000000000000000000000000000000..3476d0641224334969ccc4e3ac303d30dcead51f --- /dev/null +++ b/components/drivers/audio/audio.c @@ -0,0 +1,843 @@ +/* + * audio.c + * + * Created on: 2016年10月19日 + * Author: Urey + */ + +#include +#include +#include +#include + +#include + +#define AUDIO_DEBUG 0 +#if AUDIO_DEBUG +#define AUDIO_DBG(...) printf("[AUDIO]:"),printf(__VA_ARGS__) +#else +#define AUDIO_DBG(...) +#endif + + +rt_err_t _audio_queue_init(struct rt_audio_queue *queue, rt_uint16_t size, rt_uint16_t lwm) +{ + RT_ASSERT(queue != RT_NULL); + + queue->count = 0; + queue->size = size; + queue->lwm = lwm; + queue->waiting_lwm = RT_FALSE; + + queue->get_index = 0; + queue->put_index = 0; + + rt_list_init(&(queue->suspended_push_list)); + rt_list_init(&(queue->suspended_pop_list)); + + queue->queue = (struct rt_audio_frame *)rt_malloc(sizeof(struct rt_audio_frame) * size); + if (queue->queue == RT_NULL) + { + return -RT_ENOMEM; + } + + return RT_EOK; +} + +rt_err_t _audio_queue_push(struct rt_audio_queue *queue, struct rt_audio_frame *frame, rt_int32_t timeout) +{ + rt_ubase_t level; + rt_thread_t thread; + rt_err_t result; + + RT_ASSERT(queue != RT_NULL); + + result = RT_EOK; + thread = rt_thread_self(); + + AUDIO_DBG("%s count = %d\n",__func__,queue->count); + + level = rt_hw_interrupt_disable(); + while(queue->count == queue->size) + {// audio queue is full + queue->waiting_lwm = RT_TRUE; + + /* queue is full */ + if (timeout == 0) + { + result = -RT_ETIMEOUT; + goto __exit; + } + + /* current context checking */ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* reset thread error number */ + thread->error = RT_EOK; + + /* suspend thread on the push list */ + rt_thread_suspend(thread); + rt_list_insert_before(&(queue->suspended_push_list), &(thread->tlist)); + /* start timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do schedule */ + rt_schedule(); + + /* thread is waked up */ + result = thread->error; + level = rt_hw_interrupt_disable(); + if (result != RT_EOK) goto __exit; + } + + queue->queue[queue->put_index].data_ptr = frame->data_ptr; + queue->queue[queue->put_index].data_size = frame->data_size; + queue->queue[queue->put_index].data_ofs = frame->data_ofs; + queue->put_index = (queue->put_index + 1) % queue->size; + queue->count ++; + + if (!rt_list_isempty(&(queue->suspended_pop_list))) + { + /* there is at least one thread in suspended list */ + + /* get thread entry */ + thread = rt_list_entry(queue->suspended_pop_list.next, + struct rt_thread, + tlist); + + /* resume it */ + rt_thread_resume(thread); + rt_hw_interrupt_enable(level); + + /* perform a schedule */ + rt_schedule(); + + return result; + } +__exit: + rt_hw_interrupt_enable(level); + + return result; +} + +rt_err_t _audio_queue_pop(struct rt_audio_queue *queue, struct rt_audio_frame *frame, rt_int32_t timeout) +{ + rt_ubase_t level; + rt_thread_t thread; + rt_err_t result; + + RT_ASSERT(queue != RT_NULL); + RT_ASSERT(frame != RT_NULL); + + result = RT_EOK; + thread = rt_thread_self(); + + AUDIO_DBG("%s count = %d\n",__func__,queue->count); + + level = rt_hw_interrupt_disable(); + while (queue->count == 0) + { + /* queue is empty */ + if (timeout == 0) + { + result = -RT_ETIMEOUT; + goto __exit; + } + + /* current context checking */ + RT_DEBUG_NOT_IN_INTERRUPT; + + /* reset thread error number */ + thread->error = RT_EOK; + + /* suspend thread on the pop list */ + rt_thread_suspend(thread); + rt_list_insert_before(&(queue->suspended_pop_list), &(thread->tlist)); + /* start timer */ + if (timeout > 0) + { + /* reset the timeout of thread timer and start it */ + rt_timer_control(&(thread->thread_timer), RT_TIMER_CTRL_SET_TIME, &timeout); + rt_timer_start(&(thread->thread_timer)); + } + + /* enable interrupt */ + rt_hw_interrupt_enable(level); + + /* do schedule */ + rt_schedule(); + + /* thread is waked up */ + result = thread->error; + level = rt_hw_interrupt_disable(); + if (result != RT_EOK) + goto __exit; + } + + frame->data_ptr = queue->queue[queue->get_index].data_ptr; + frame->data_size = queue->queue[queue->get_index].data_size; + frame->data_ofs = queue->queue[queue->get_index].data_ofs; + + queue->get_index = (queue->get_index + 1) % queue->size; + queue->count --; + + if ((queue->waiting_lwm == RT_TRUE) && + (queue->put_index - queue->get_index) <= queue->lwm) + { + queue->waiting_lwm = RT_FALSE; + + /* + * there is at least one thread in suspended list + * and less than low water mark + */ + if (!rt_list_isempty(&(queue->suspended_push_list))) + { + /* get thread entry */ + thread = rt_list_entry(queue->suspended_push_list.next, + struct rt_thread, + tlist); + + /* resume it */ + rt_thread_resume(thread); + rt_hw_interrupt_enable(level); + + /* perform a schedule */ + rt_schedule(); + } + + return result; + } +__exit: + rt_hw_interrupt_enable(level); + return result; +} + +rt_err_t _audio_queue_peak(struct rt_audio_queue *queue, struct rt_audio_frame *frame) +{ + rt_ubase_t level; + + RT_ASSERT(queue != RT_NULL); + + AUDIO_DBG("%s count = %d\n",__func__,queue->count); + + level = rt_hw_interrupt_disable(); + if (queue->count == 0) + { + rt_hw_interrupt_enable(level); + + return -RT_EEMPTY; + } + + frame->data_ptr = queue->queue[queue->get_index].data_ptr; + frame->data_size = queue->queue[queue->get_index].data_size; + frame->data_ofs = queue->queue[queue->get_index].data_ofs; + + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t _audio_queue_unpeak(struct rt_audio_queue *queue, struct rt_audio_frame *frame) +{ + rt_ubase_t level; + + RT_ASSERT(queue != RT_NULL); + + level = rt_hw_interrupt_disable(); + + if (queue->count == 0) + { + rt_hw_interrupt_enable(level); + + return -RT_EEMPTY; + } + + queue->queue[queue->get_index].data_ptr = frame->data_ptr; + queue->queue[queue->get_index].data_size = frame->data_size; + queue->queue[queue->get_index].data_ofs = frame->data_ofs; + + rt_hw_interrupt_enable(level); + + return RT_EOK; +} + +rt_err_t _audio_queue_reset(struct rt_audio_queue *queue) +{ + struct rt_thread *thread; + register rt_ubase_t temp; + + rt_enter_critical(); + + /* wakeup all suspend threads */ + /* resume on pop list */ + while (!rt_list_isempty(&(queue->suspended_pop_list))) + { + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(queue->suspended_pop_list.next, + struct rt_thread, + tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + /* + * resume thread + * In rt_thread_resume function, it will remove current thread from + * suspend list + */ + rt_thread_resume(thread); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + + /* resume on push list */ + while (!rt_list_isempty(&(queue->suspended_push_list))) + { + /* disable interrupt */ + temp = rt_hw_interrupt_disable(); + + /* get next suspend thread */ + thread = rt_list_entry(queue->suspended_push_list.next, + struct rt_thread, + tlist); + /* set error code to RT_ERROR */ + thread->error = -RT_ERROR; + + /* + * resume thread + * In rt_thread_resume function, it will remove current thread from + * suspend list + */ + rt_thread_resume(thread); + + /* enable interrupt */ + rt_hw_interrupt_enable(temp); + } + rt_exit_critical(); + + rt_schedule(); +} + + +static rt_err_t _audio_send_replay_frame(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + rt_base_t level; + struct rt_audio_frame frame; + + RT_ASSERT(audio != RT_NULL); + + //check repaly queue is empty + if(_audio_queue_peak(&audio->replay->queue,&frame) != RT_EOK) + { + AUDIO_DBG("TX queue is empty\n"); + result = -RT_EEMPTY; + + level = rt_hw_interrupt_disable(); + audio->replay->activated = RT_FALSE; + rt_hw_interrupt_enable(level); + + goto _exit; + } + + if(audio->ops->transmit != RT_NULL) + { + AUDIO_DBG("audio transmit...\n"); + if(audio->ops->transmit(audio,frame.data_ptr,RT_NULL, frame.data_size) != frame.data_size) + { + result = -RT_EBUSY; + + goto _exit; + } + } + + //pop the head frame... + _audio_queue_pop(&audio->replay->queue,&frame,RT_WAITING_NO); + +_exit: + return result; +} + +static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio) +{ + struct rt_audio_frame frame; + + if(audio->replay == RT_NULL) + return -RT_EIO; + + while(_audio_queue_peak(&audio->replay->queue,&frame) == RT_EOK) + { + //pop the head frame... + _audio_queue_pop(&audio->replay->queue,&frame,RT_WAITING_NO); + + /* notify transmitted complete. */ + if(audio->parent.tx_complete != RT_NULL) + audio->parent.tx_complete(&audio->parent,(void *)frame.data_ptr); + } + + return RT_EOK; +} + +static rt_err_t _audio_dev_init(struct rt_device *dev) +{ + rt_err_t result = RT_EOK; + struct rt_audio_device *audio; + + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + + /* initialize replay & record */ + audio->replay = RT_NULL; + audio->record = RT_NULL; + + /* apply configuration */ + if (audio->ops->init) + result = audio->ops->init(audio); + + return result; +} + +static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag) +{ + rt_err_t result = RT_EOK; + rt_base_t level; + struct rt_audio_device *audio; + + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + + /* check device flag with the open flag */ + if ((oflag & RT_DEVICE_OFLAG_RDONLY) && !(dev->flag & RT_DEVICE_FLAG_RDONLY)) + return -RT_EIO; + if ((oflag & RT_DEVICE_OFLAG_WRONLY) && !(dev->flag & RT_DEVICE_FLAG_WRONLY)) + return -RT_EIO; + + /* get open flags */ + dev->open_flag = oflag & 0xff; + + /* initialize the Rx/Tx structure according to open flag */ + if (oflag & RT_DEVICE_OFLAG_WRONLY) + { + AUDIO_DBG("open audio device ,oflag = %x\n",oflag); + if(audio->replay == RT_NULL) + { + struct rt_audio_replay *replay = (struct rt_audio_replay *)rt_malloc(sizeof(struct rt_audio_replay)); + + if(replay == RT_NULL) + { + AUDIO_DBG("request memory for replay error\n"); + return -RT_ENOMEM; + } + + //init queue for audio replay + _audio_queue_init(&replay->queue,CFG_AUDIO_REPLAY_QUEUE_COUNT,CFG_AUDIO_REPLAY_QUEUE_COUNT / 2); + + replay->activated = RT_FALSE; + audio->replay = replay; + } + + dev->open_flag |= RT_DEVICE_OFLAG_WRONLY; + } + + if(oflag & RT_DEVICE_OFLAG_RDONLY) + { + if(audio->record == RT_NULL) + { + struct rt_audio_record *record = (struct rt_audio_record *)rt_malloc(sizeof(struct rt_audio_record)); + + if(record == RT_NULL) + { + AUDIO_DBG("request memory for record error\n"); + return -RT_ENOMEM; + } + + //init pipe for record + { + rt_size_t size = CFG_AUDIO_RECORD_PIPE_SIZE; + rt_uint8_t *buf = rt_malloc(CFG_AUDIO_RECORD_PIPE_SIZE); + + if(buf == RT_NULL) + { + rt_free(record); + AUDIO_DBG("request pipe memory error\n"); + + return -RT_ENOMEM; + } + + rt_pipe_init(&record->pipe,"recpipe",RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD,buf,CFG_AUDIO_RECORD_PIPE_SIZE); + } + + record->activated = RT_FALSE; + audio->record = record; + } + + //open record pipe + if(audio->record != RT_NULL) + { + rt_device_open(RT_DEVICE(&audio->record->pipe),RT_DEVICE_OFLAG_RDONLY); + } + + dev->open_flag |= RT_DEVICE_OFLAG_RDONLY; + } + + return RT_EOK; +} + +static rt_err_t _audio_dev_close(struct rt_device *dev) +{ + struct rt_audio_device *audio; + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + + //shutdown the lower device + if(audio->ops->shutdown != RT_NULL) + audio->ops->shutdown(audio); + + if(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) + { + struct rt_audio_frame frame; + //stop replay stream + audio->ops->stop(audio,AUDIO_STREAM_REPLAY); + + //flush all frame + while(_audio_queue_peak(&audio->replay->queue,&frame) == RT_EOK) + { + _audio_queue_pop(&audio->replay->queue,&frame,RT_WAITING_NO); + + //indicate this frame complete(maybe upper device need free data) + if(dev->tx_complete != RT_NULL) + dev->tx_complete(dev,(void *)frame.data_ptr); + } + + dev->open_flag &= ~RT_DEVICE_OFLAG_WRONLY; + } + + if(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) + { + //stop record stream + audio->ops->stop(audio,AUDIO_STREAM_RECORD); + + //close record pipe + if(audio->record != RT_NULL) + rt_device_close(RT_DEVICE(&audio->record->pipe)); + + dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY; + } + + return RT_EOK; +} + +static rt_size_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buffer, rt_size_t size) +{ + struct rt_audio_device *audio; + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + if(!(dev->open_flag & RT_DEVICE_OFLAG_RDONLY) || (audio->record == RT_NULL)) + return 0; + + return rt_device_read(RT_DEVICE(&audio->record->pipe), pos, buffer, size); +} + +static rt_size_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const void *buffer, rt_size_t size) +{ + rt_err_t result = RT_EOK; + rt_base_t level; + struct rt_audio_device *audio; + + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + + if(!(dev->open_flag & RT_DEVICE_OFLAG_WRONLY) || (audio->replay == RT_NULL)) + return 0; + + AUDIO_DBG("audio write : pos = %d,buffer = %x,size = %d\n",pos,(rt_uint32_t)buffer,size); + //push a new frame to tx queue + { + struct rt_audio_frame frame; + frame.data_ptr = buffer; + frame.data_size = size; + frame.data_ofs = 0; + + result = _audio_queue_push(&audio->replay->queue,&frame,RT_WAITING_FOREVER); + if(result != RT_EOK) + { + AUDIO_DBG("TX frame queue push error\n"); + rt_set_errno(-RT_EFULL); + return 0; + } + } + + //check tx state... + level = rt_hw_interrupt_disable(); + if(audio->replay->activated != RT_TRUE) + { + audio->replay->activated = RT_TRUE; + rt_hw_interrupt_enable(level); + + _audio_send_replay_frame(audio); + } + + return size; +} + +static rt_err_t _audio_dev_control(struct rt_device *dev, rt_uint8_t cmd, void *args) +{ + rt_err_t result = RT_EOK; + struct rt_audio_device *audio; + RT_ASSERT(dev != RT_NULL); + audio = (struct rt_audio_device *)dev; + + //dev stat... + switch (cmd) + { + case AUDIO_CTL_GETCAPS: + { + struct rt_audio_caps *caps = (struct rt_audio_caps *) args; + + AUDIO_DBG("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d\n",caps->main_type,caps->sub_type); + if (audio->ops->getcaps != RT_NULL) + { + result = audio->ops->getcaps(audio, caps); + } + } + break; + case AUDIO_CTL_CONFIGURE: + { + struct rt_audio_caps *caps = (struct rt_audio_caps *) args; + + AUDIO_DBG("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d\n",caps->main_type,caps->sub_type); + if (audio->ops->configure != RT_NULL) + { + result = audio->ops->configure(audio, caps); + } + } + + break; + case AUDIO_CTL_SHUTDOWN: + { + AUDIO_DBG("AUDIO_CTL_SHUTDOWN\n"); + + if (audio->ops->shutdown != RT_NULL) + result = audio->ops->shutdown(audio); + + //flush replay frame... + _audio_flush_replay_frame(audio); + } + break; + + case AUDIO_CTL_START: + { + int stream = *(int *) args; + + AUDIO_DBG("AUDIO_CTL_START: stream = %d\n",stream); + if (audio->ops->start != RT_NULL) + result = audio->ops->start(audio, stream); + } + break; + case AUDIO_CTL_STOP: + { + int stream = *(int *) args; + + AUDIO_DBG("AUDIO_CTL_STOP: stream = %d\n",stream); + if (audio->ops->start != RT_NULL) + result = audio->ops->stop(audio, stream); + + if(stream == AUDIO_STREAM_REPLAY) + { + _audio_flush_replay_frame(audio); + } + } + break; + case AUDIO_CTL_PAUSE: + { + int stream = *(int *) args; + + AUDIO_DBG("AUDIO_CTL_PAUSE: stream = %d\n",stream); + if (audio->ops->start != RT_NULL) + result = audio->ops->suspend(audio, stream); + } + break; + case AUDIO_CTL_RESUME: + { + int stream = *(int *) args; + + AUDIO_DBG("AUDIO_CTL_RESUME: stream = %d\n",stream); + if (audio->ops->start != RT_NULL) + result = audio->ops->resume(audio, stream); + + //resume tx frame... + if(stream == AUDIO_STREAM_REPLAY) + _audio_send_replay_frame(audio); + } + break; +#ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER + case AUDIO_CTL_ALLOCBUFFER: + { + struct rt_audio_buf_desc *desc = (struct rt_audio_buf_desc *)args; + + if((audio->ops->buffer_alloc != RT_NULL) && (desc != RT_NULL)) + { + result = audio->ops->buffer_alloc(audio,&desc->data_ptr,&desc->data_size); + break; + } + + result = -RT_EIO; + } + break; + case AUDIO_CTL_FREEBUFFER: + { + rt_uint8_t *data_ptr = (rt_uint8_t *)args; + if((audio->ops->buffer_free != RT_NULL) && (data_ptr != RT_NULL)) + { + audio->ops->buffer_free(audio,data_ptr); + break; + } + } + break; +#endif + default: + result = audio->ops->control(audio, cmd, args); + break; + } + + return result; +} + + +rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data) +{ + struct rt_device *device; + RT_ASSERT(audio != RT_NULL); + device = &(audio->parent); + + device->type = RT_Device_Class_Sound; + device->rx_indicate = RT_NULL; + device->tx_complete = RT_NULL; + + device->init = _audio_dev_init; + device->open = _audio_dev_open; + device->close = _audio_dev_close; + device->read = _audio_dev_read; + device->write = _audio_dev_write; + device->control = _audio_dev_control; + device->user_data = data; + + /* register a character device */ + return rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE); +} + + + +rt_size_t rt_audio_get_buffer_size(struct rt_audio_device *audio) +{ +// return (audio->config.period_count * audio->config.period_size); + return 0; +} + +int rt_audio_samplerate_to_speed(rt_uint32_t bitValue) +{ + int speed = 0; + switch (bitValue) + { + case AUDIO_SAMP_RATE_8K: + speed = 8000; + break; + case AUDIO_SAMP_RATE_11K: + speed = 11052; + break; + case AUDIO_SAMP_RATE_16K: + speed = 16000; + break; + case AUDIO_SAMP_RATE_22K: + speed = 22050; + break; + case AUDIO_SAMP_RATE_32K: + speed = 32000; + break; + case AUDIO_SAMP_RATE_44K: + speed = 44100; + break; + case AUDIO_SAMP_RATE_48K: + speed = 48000; + break; + case AUDIO_SAMP_RATE_96K: + speed = 96000; + break; + case AUDIO_SAMP_RATE_128K: + speed = 128000; + break; + case AUDIO_SAMP_RATE_160K: + speed = 160000; + break; + case AUDIO_SAMP_RATE_172K: + speed = 176400; + break; + case AUDIO_SAMP_RATE_192K: + speed = 192000; + break; + default: + + break; + } + + return speed; +} + + + +rt_uint32_t rt_audio_format_to_bits(rt_uint32_t format) +{ + switch (format) + { + case AUDIO_FMT_PCM_U8: + case AUDIO_FMT_PCM_S8: + return 8; + case AUDIO_FMT_PCM_S16_LE: + case AUDIO_FMT_PCM_S16_BE: + case AUDIO_FMT_PCM_U16_LE: + case AUDIO_FMT_PCM_U16_BE: + return 16; + default: + return 32; + }; +} + +void rt_audio_tx_complete(struct rt_audio_device *audio,rt_uint8_t *pbuf) +{ + rt_err_t result; + AUDIO_DBG("audio tx complete ptr=%x...\n",(rt_uint32_t)pbuf); + + //try to send all frame + do + { + result = _audio_send_replay_frame(audio); + }while(result == RT_EOK); + + /* notify transmitted complete. */ + if(audio->parent.tx_complete != RT_NULL) + audio->parent.tx_complete(&audio->parent,(void *)pbuf); +} + +void rt_audio_rx_done(struct rt_audio_device *audio,rt_uint8_t *pbuf,rt_size_t len) +{ + rt_err_t result = RT_EOK; + + //save data to record pipe + rt_device_write(RT_DEVICE(RT_DEVICE(&audio->record->pipe)),0,pbuf,len); + + /* invoke callback */ + if(audio->parent.rx_indicate != RT_NULL) + audio->parent.rx_indicate(&audio->parent,len); +} + diff --git a/components/drivers/include/drivers/audio.h b/components/drivers/include/drivers/audio.h index 3836ab3fd21af3e73a33fde111311ae319c7da96..7d715799ba4c9b3c2542fb3dd1cba0b7c7686807 100644 --- a/components/drivers/include/drivers/audio.h +++ b/components/drivers/include/drivers/audio.h @@ -1,5 +1,216 @@ -#ifndef AUDIO_H__ -#define AUDIO_H__ +#ifndef __AUDIO_H__ +#define __AUDIO_H__ + +//#define AUDIO_DEVICE_USE_PRIVATE_BUFFER + + +/* AUDIO command */ +#define _AUDIO_CTL(a) (0x10 + a) + +#define AUDIO_CTL_GETCAPS _AUDIO_CTL(1) +#define AUDIO_CTL_CONFIGURE _AUDIO_CTL(2) +#define AUDIO_CTL_SHUTDOWN _AUDIO_CTL(3) +#define AUDIO_CTL_START _AUDIO_CTL(4) +#define AUDIO_CTL_STOP _AUDIO_CTL(5) +#define AUDIO_CTL_PAUSE _AUDIO_CTL(6) +#define AUDIO_CTL_RESUME _AUDIO_CTL(7) +#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(8) +#define AUDIO_CTL_ALLOCBUFFER _AUDIO_CTL(9) +#define AUDIO_CTL_FREEBUFFER _AUDIO_CTL(10) +#define AUDIO_CTL_HWRESET _AUDIO_CTL(11) + + +/* Audio Device Types */ +#define AUDIO_TYPE_QUERY 0x00 +#define AUDIO_TYPE_INPUT 0x01 +#define AUDIO_TYPE_OUTPUT 0x02 +#define AUDIO_TYPE_MIXER 0x04 +#define AUDIO_TYPE_SELECTOR 0x08 +#define AUDIO_TYPE_EFFECT 0x10 + +/* Audio Format Types */ +#define AUDIO_FMT_PCM_U8 0x0001 +#define AUDIO_FMT_PCM_S8 0x0002 + +#define AUDIO_FMT_PCM_U16_LE 0x0010 +#define AUDIO_FMT_PCM_S16_BE 0x0020 +#define AUDIO_FMT_PCM_S16_LE 0x0040 +#define AUDIO_FMT_PCM_U16_BE 0x0080 +#define AUDIO_FMT_PCM_U24_LE 0x0100 +#define AUDIO_FMT_PCM_S24_BE 0x0200 +#define AUDIO_FMT_PCM_S24_LE 0x0400 +#define AUDIO_FMT_PCM_U24_BE 0x0800 +#define AUDIO_FMT_PCM_U32_LE 0x1000 +#define AUDIO_FMT_PCM_S32_BE 0x2000 +#define AUDIO_FMT_PCM_S32_LE 0x4000 +#define AUDIO_FMT_PCM_U32_BE 0x8000 + +/* Supported Sampling Rates */ +#define AUDIO_SAMP_RATE_8K 0x0001 +#define AUDIO_SAMP_RATE_11K 0x0002 +#define AUDIO_SAMP_RATE_16K 0x0004 +#define AUDIO_SAMP_RATE_22K 0x0008 +#define AUDIO_SAMP_RATE_32K 0x0010 +#define AUDIO_SAMP_RATE_44K 0x0020 +#define AUDIO_SAMP_RATE_48K 0x0040 +#define AUDIO_SAMP_RATE_96K 0x0080 +#define AUDIO_SAMP_RATE_128K 0x0100 +#define AUDIO_SAMP_RATE_160K 0x0200 +#define AUDIO_SAMP_RATE_172K 0x0400 +#define AUDIO_SAMP_RATE_192K 0x0800 + +/* Supported Bit Rates */ +#define AUDIO_BIT_RATE_22K 0x01 +#define AUDIO_BIT_RATE_44K 0x02 +#define AUDIO_BIT_RATE_48K 0x04 +#define AUDIO_BIT_RATE_96K 0x08 +#define AUDIO_BIT_RATE_128K 0x10 +#define AUDIO_BIT_RATE_160K 0x20 +#define AUDIO_BIT_RATE_172K 0x40 +#define AUDIO_BIT_RATE_192K 0x80 + + + +/* Support Dsp(input/output) Units controls */ +#define AUDIO_DSP_PARAM 0 /* get/set all params */ +#define AUDIO_DSP_SAMPLERATE 1 /* 采样频率 */ +#define AUDIO_DSP_FMT 2 +#define AUDIO_DSP_CHANNELS 3 + +/* Supported Mixer Units controls */ +#define AUDIO_MIXER_QUERY 0x0000 +#define AUDIO_MIXER_MUTE 0x0001 +#define AUDIO_MIXER_VOLUME 0x0002 +#define AUDIO_MIXER_BASS 0x0004 +#define AUDIO_MIXER_MID 0x0008 +#define AUDIO_MIXER_TREBLE 0x0010 +#define AUDIO_MIXER_EQUALIZER 0x0020 +#define AUDIO_MIXER_LINE 0x0040 +#define AUDIO_MIXER_DIGITAL 0x0080 +#define AUDIO_MIXER_MIC 0x0100 + +#define AUDIO_MIXER_EXTEND 0x8000 //extend mixer command + +#define CFG_AUDIO_REPLAY_QUEUE_COUNT 4 +#define CFG_AUDIO_RECORD_PIPE_SIZE (8 * 1024) + +enum +{ + AUDIO_STREAM_REPLAY = 0, + AUDIO_STREAM_RECORD, + AUDIO_STREAM_LAST = AUDIO_STREAM_RECORD, +}; + +/* the preferred number and size of audio pipeline buffer for the audio device */ +struct rt_audio_buf_info +{ + rt_uint32_t buffer_size; /* Preferred qty of buffers */ + rt_uint32_t buffer_count; /* Preferred size of the buffers */ +}; +struct rt_audio_buf_desc +{ + rt_uint8_t *data_ptr; + rt_size_t data_size; +}; + +struct rt_audio_frame +{ + const void *data_ptr; + rt_size_t data_size; + rt_size_t data_ofs; +}; + +struct rt_audio_queue +{ + rt_uint16_t count; + rt_uint16_t size; + rt_uint16_t lwm; + rt_bool_t waiting_lwm; + + rt_uint16_t get_index; + rt_uint16_t put_index; + + struct rt_audio_frame *queue; + + rt_list_t suspended_push_list; + rt_list_t suspended_pop_list; +}; + +struct rt_audio_device; +struct rt_audio_caps; +struct rt_audio_configure; +struct rt_audio_ops +{ + rt_err_t (*getcaps) (struct rt_audio_device *audio,struct rt_audio_caps *caps); + rt_err_t (*configure) (struct rt_audio_device *audio,struct rt_audio_caps *caps); + + rt_err_t (*init) (struct rt_audio_device *audio); + rt_err_t (*shutdown) (struct rt_audio_device *audio); + rt_err_t (*start) (struct rt_audio_device *audio,int stream); + rt_err_t (*stop) (struct rt_audio_device *audio,int stream); + rt_err_t (*suspend) (struct rt_audio_device *audio,int stream); + rt_err_t (*resume) (struct rt_audio_device *audio,int stream); + + rt_err_t (*control) (struct rt_audio_device *audio, rt_uint8_t cmd, void *arg); + rt_size_t (*transmit) (struct rt_audio_device *audio, const void *writeBuf,void *readBuf, rt_size_t size); + + //get page size of codec or private buffer's info + void (*buffer_info) (struct rt_audio_device *audio,struct rt_audio_buf_info *info ); +#ifdef AUDIO_DEVICE_USE_PRIVATE_BUFFER + rt_err_t (*buffer_alloc) (struct rt_audio_device *audio,rt_uint8_t **data_ptr,rt_size_t *size); + void (*buffer_free) (struct rt_audio_device *audio,rt_uint8_t *data_ptr); +#endif +}; + + +struct rt_audio_configure +{ + rt_uint32_t channels; + + rt_uint32_t samplefmt; + rt_uint32_t samplerate; + rt_uint32_t samplefmts; +}; + +struct rt_audio_caps +{ + int main_type; + int sub_type; + + union + { + rt_uint32_t mask; + int value; + struct rt_audio_configure config; + }udata; +}; + +struct rt_audio_replay +{ + rt_bool_t activated; + struct rt_audio_queue queue; +}; + +struct rt_audio_record +{ + rt_bool_t activated; + struct rt_pipe_device pipe; +}; + +struct rt_audio_device +{ + struct rt_device parent; + struct rt_audio_ops *ops; + + struct rt_audio_replay *replay; + struct rt_audio_record *record; +}; + +rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data); +void rt_audio_tx_complete(struct rt_audio_device *audio,rt_uint8_t *pbuf); +void rt_audio_rx_done(struct rt_audio_device *audio,rt_uint8_t *pbuf,rt_size_t len); +rt_uint32_t rt_audio_format_to_bits(rt_uint32_t format); + /* Device Control Commands */ #define CODEC_CMD_RESET 0 @@ -11,4 +222,4 @@ #define CODEC_VOLUME_MAX (63) -#endif +#endif /* __AUDIO_H__ */