diff --git a/bsp/x1000/.config b/bsp/x1000/.config index 9a5600a15e..5687c56695 100644 --- a/bsp/x1000/.config +++ b/bsp/x1000/.config @@ -334,6 +334,6 @@ CONFIG_RT_USING_I2C0=y # CONFIG_RT_USING_TRULY_TFT240240 is not set # CONFIG_RT_USING_GT9XX is not set # CONFIG_RT_USING_FT6x06 is not set -CONFIG_RT_USING_AUDIO=y +# CONFIG_RT_USING_AUDIO is not set CONFIG_RT_USING_ICODEC=y CONFIG_RT_USING_CPU_FFS=y diff --git a/bsp/x1000/rtconfig.h b/bsp/x1000/rtconfig.h index e7c3e5feda..52cc228c70 100644 --- a/bsp/x1000/rtconfig.h +++ b/bsp/x1000/rtconfig.h @@ -300,7 +300,7 @@ /* RT_USING_TRULY_TFT240240 is not set */ /* RT_USING_GT9XX is not set */ /* RT_USING_FT6x06 is not set */ -#define RT_USING_AUDIO +/* RT_USING_AUDIO is not set */ #define RT_USING_ICODEC #define RT_USING_CPU_FFS diff --git a/components/drivers/Kconfig b/components/drivers/Kconfig index 4aceee3b4e..250d661e9f 100755 --- a/components/drivers/Kconfig +++ b/components/drivers/Kconfig @@ -238,6 +238,20 @@ config RT_USING_WDT config RT_USING_AUDIO bool "Using Audio device drivers" default n + + if RT_USING_AUDIO + config RT_AUDIO_REPLAY_MP_BLOCK_SIZE + int "Replay memmory pool block size" + default 4096 + + config RT_AUDIO_REPLAY_MP_BLOCK_COUNT + int "Replay memmory pool block count" + default 2 + + config RT_AUDIO_RECORD_PIPE_SIZE + int "Record pipe size" + default 2048 + endif config RT_USING_SENSOR bool "Using Sensor device drivers" diff --git a/components/drivers/audio/audio.c b/components/drivers/audio/audio.c index 6da0a3da91..28ddf0fe56 100644 --- a/components/drivers/audio/audio.c +++ b/components/drivers/audio/audio.c @@ -5,83 +5,208 @@ * * Change Logs: * Date Author Notes - * 2017-05-09 Urey first version + * 2017-05-09 Urey first version + * 2019-07-09 Zero-Free improve device ops interface and data flows */ #include +#include #include #include #include -#include +#define DBG_TAG "audio" +#define DBG_LVL DBG_INFO +#include -#include "audio_pipe.h" +#define MIN(a, b) ((a) < (b) ? (a) : (b)) - -#define AUDIO_DEBUG 0 -#if AUDIO_DEBUG -#define AUDIO_DBG(...) printf("[AUDIO]:"),printf(__VA_ARGS__) -#else -#define AUDIO_DBG(...) -#endif - -static struct rt_audio_pipe audio_pipe; +enum +{ + REPLAY_EVT_NONE = 0x00, + REPLAY_EVT_START = 0x01, + REPLAY_EVT_STOP = 0x02, +}; 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_uint8_t *data; + rt_size_t dst_size, src_size; + rt_uint16_t position, remain_bytes, index = 0; + struct rt_audio_buf_info *buf_info; RT_ASSERT(audio != RT_NULL); - //check repaly queue is empty - if (rt_data_queue_peak(&audio->replay->queue, &frame.data_ptr, &frame.data_size) != RT_EOK) + buf_info = &audio->replay->buf_info; + /* save current pos */ + position = audio->replay->pos; + dst_size = buf_info->block_size; + + /* check repaly queue is empty */ + if (rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size) != RT_EOK) { - AUDIO_DBG("TX queue is empty\n"); - result = -RT_EEMPTY; + /* ack stop event */ + if (audio->replay->event & REPLAY_EVT_STOP) + rt_completion_done(&audio->replay->cmp); - level = rt_hw_interrupt_disable(); - audio->replay->activated = RT_FALSE; - rt_hw_interrupt_enable(level); + /* send zero frames */ + memset(&buf_info->buffer[audio->replay->pos], 0, dst_size); - goto _exit; + audio->replay->pos += dst_size; + audio->replay->pos %= buf_info->total_size; + } + else + { + memset(&buf_info->buffer[audio->replay->pos], 0, dst_size); + + /* copy data from memory pool to hardware device fifo */ + while (index < dst_size) + { + result = rt_data_queue_peak(&audio->replay->queue, (const void **)&data, &src_size); + if (result != RT_EOK) + { + LOG_D("under run %d, remain %d", audio->replay->pos, remain_bytes); + audio->replay->pos -= remain_bytes; + audio->replay->pos += dst_size; + audio->replay->pos %= buf_info->total_size; + audio->replay->read_index = 0; + result = -RT_EEMPTY; + break; + } + + remain_bytes = MIN((dst_size - index), (src_size - audio->replay->read_index)); + memcpy(&buf_info->buffer[audio->replay->pos], + &data[audio->replay->read_index], remain_bytes); + + index += remain_bytes; + audio->replay->read_index += remain_bytes; + audio->replay->pos += remain_bytes; + audio->replay->pos %= buf_info->total_size; + + if (audio->replay->read_index == src_size) + { + /* free memory */ + audio->replay->read_index = 0; + rt_data_queue_pop(&audio->replay->queue, (const void **)&data, &src_size, RT_WAITING_NO); + rt_mp_free(data); + + /* notify transmitted complete. */ + if (audio->parent.tx_complete != RT_NULL) + audio->parent.tx_complete(&audio->parent, (void *)data); + } + } } 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; - } + if (audio->ops->transmit(audio, &buf_info->buffer[position], RT_NULL, dst_size) != dst_size) + result = -RT_ERROR; } - //pop the head frame... - rt_data_queue_pop(&audio->replay->queue, &frame.data_ptr, &frame.data_size, RT_WAITING_FOREVER); - - _exit: return result; + return result; } static rt_err_t _audio_flush_replay_frame(struct rt_audio_device *audio) { - struct rt_audio_frame frame; + rt_err_t result = RT_EOK; - if (audio->replay == RT_NULL) - return -RT_EIO; - while (rt_data_queue_peak(&audio->replay->queue, &frame.data_ptr, &frame.data_size) == RT_EOK) + if (audio->replay->write_index) { - //pop the head frame... - rt_data_queue_pop(&audio->replay->queue, &frame.data_ptr, &frame.data_size, RT_WAITING_FOREVER); + result = rt_data_queue_push(&audio->replay->queue, + (const void **)audio->replay->write_data, + audio->replay->write_index, + RT_WAITING_FOREVER); - /* notify transmitted complete. */ - if (audio->parent.tx_complete != RT_NULL) - audio->parent.tx_complete(&audio->parent, (void *) frame.data_ptr); + audio->replay->write_index = 0; } - return RT_EOK; + return result; +} + +static rt_err_t _aduio_replay_start(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + + if (audio->replay->activated != RT_TRUE) + { + /* start playback hardware device */ + if (audio->ops->start) + result = audio->ops->start(audio, AUDIO_STREAM_REPLAY); + + audio->replay->activated = RT_TRUE; + LOG_D("start audio replay device"); + } + + return result; +} + +static rt_err_t _aduio_replay_stop(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + + if (audio->replay->activated == RT_TRUE) + { + /* flush replay remian frames */ + _audio_flush_replay_frame(audio); + + /* notify irq(or thread) to stop the data transmission */ + audio->replay->event |= REPLAY_EVT_STOP; + + /* waiting for the remaining data transfer to complete */ + rt_completion_init(&audio->replay->cmp); + rt_completion_wait(&audio->replay->cmp, RT_WAITING_FOREVER); + audio->replay->event &= ~REPLAY_EVT_STOP; + + /* stop playback hardware device */ + if (audio->ops->stop) + result = audio->ops->stop(audio, AUDIO_STREAM_REPLAY); + + audio->replay->activated = RT_FALSE; + LOG_D("stop audio replay device"); + } + + return result; +} + +static rt_err_t _audio_record_start(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + + if (audio->record->activated != RT_TRUE) + { + /* open audio record pipe */ + rt_device_open(RT_DEVICE(&audio->record->pipe), RT_DEVICE_OFLAG_RDONLY); + + /* start record hardware device */ + if (audio->ops->start) + result = audio->ops->start(audio, AUDIO_STREAM_RECORD); + + audio->record->activated = RT_TRUE; + LOG_D("start audio record device"); + } + + return result; +} + +static rt_err_t _audio_record_stop(struct rt_audio_device *audio) +{ + rt_err_t result = RT_EOK; + + if (audio->record->activated == RT_TRUE) + { + /* stop record hardware device */ + if (audio->ops->stop) + result = audio->ops->stop(audio, AUDIO_STREAM_RECORD); + + /* close audio record pipe */ + rt_device_close(RT_DEVICE(&audio->record->pipe)); + + audio->record->activated = RT_FALSE; + LOG_D("stop audio record device"); + } + + return result; } static rt_err_t _audio_dev_init(struct rt_device *dev) @@ -96,9 +221,68 @@ static rt_err_t _audio_dev_init(struct rt_device *dev) audio->replay = RT_NULL; audio->record = RT_NULL; - /* apply configuration */ + /* initialize replay */ + if (dev->flag & RT_DEVICE_FLAG_WRONLY) + { + struct rt_audio_replay *replay = (struct rt_audio_replay *) rt_malloc(sizeof(struct rt_audio_replay)); + + if (replay == RT_NULL) + return -RT_ENOMEM; + memset(replay, 0, sizeof(struct rt_audio_replay)); + + /* init memory pool for replay */ + replay->mp = rt_mp_create("adu_mp", RT_AUDIO_REPLAY_MP_BLOCK_COUNT, RT_AUDIO_REPLAY_MP_BLOCK_SIZE); + if (replay->mp == RT_NULL) + { + rt_free(replay); + LOG_E("create memory pool for repaly failed"); + return -RT_ENOMEM; + } + + /* init queue for audio replay */ + rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, 0, RT_NULL); + + /* init mutex lock for audio replay */ + rt_mutex_init(&replay->lock, "replay", RT_IPC_FLAG_PRIO); + + replay->activated = RT_FALSE; + audio->replay = replay; + } + + /* initialize record */ + if (dev->flag & RT_DEVICE_FLAG_RDONLY) + { + struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record)); + rt_uint8_t *buffer; + + if (record == RT_NULL) + return -RT_ENOMEM; + memset(record, 0, sizeof(struct rt_audio_record)); + + /* init pipe for record*/ + buffer = rt_malloc(RT_AUDIO_RECORD_PIPE_SIZE); + if (buffer == RT_NULL) + { + rt_free(record); + LOG_E("malloc memory for for record pipe failed"); + return -RT_ENOMEM; + } + rt_audio_pipe_init(&record->pipe, "record", + (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD), + buffer, + RT_AUDIO_RECORD_PIPE_SIZE); + + record->activated = RT_FALSE; + audio->record = record; + } + + /* initialize hardware configuration */ if (audio->ops->init) - result = audio->ops->init(audio); + audio->ops->init(audio); + + /* get replay buffer information */ + if (audio->ops->buffer_info) + audio->ops->buffer_info(audio, &audio->replay->buf_info); return result; } @@ -122,65 +306,27 @@ static rt_err_t _audio_dev_open(struct rt_device *dev, rt_uint16_t oflag) /* 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) + if (audio->replay->activated != RT_TRUE) { - 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 - rt_data_queue_init(&replay->queue, CFG_AUDIO_REPLAY_QUEUE_COUNT, CFG_AUDIO_REPLAY_QUEUE_COUNT / 2, RT_NULL); - - replay->activated = RT_FALSE; - audio->replay = replay; + LOG_D("open audio replay device, oflag = %x\n", oflag); + audio->replay->write_index = 0; + audio->replay->read_index = 0; + audio->replay->pos = 0; + audio->replay->event = REPLAY_EVT_NONE; } - dev->open_flag |= RT_DEVICE_OFLAG_WRONLY; } if (oflag & RT_DEVICE_OFLAG_RDONLY) { - if (audio->record == RT_NULL) + /* open record pipe */ + if (audio->record->activated != RT_TRUE) { - struct rt_audio_record *record = (struct rt_audio_record *) rt_malloc(sizeof(struct rt_audio_record)); + LOG_D("open audio record device ,oflag = %x\n", oflag); - if (record == RT_NULL) - { - AUDIO_DBG("request memory for record error\n"); - return -RT_ENOMEM; - } - - //init pipe for record - { - rt_uint8_t *buf = (rt_uint8_t *)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_audio_pipe_init(&audio_pipe, "recpipe", (rt_int32_t)(RT_PIPE_FLAG_FORCE_WR | RT_PIPE_FLAG_BLOCK_RD), buf, - CFG_AUDIO_RECORD_PIPE_SIZE); - } - - record->activated = RT_FALSE; - audio->record = record; + _audio_record_start(audio); + audio->record->activated = RT_TRUE; } - - //open record pipe - if (audio->record != RT_NULL) - { - rt_device_open(RT_DEVICE(&audio_pipe), RT_DEVICE_OFLAG_RDONLY); - } - dev->open_flag |= RT_DEVICE_OFLAG_RDONLY; } @@ -193,39 +339,17 @@ static rt_err_t _audio_dev_close(struct rt_device *dev) 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 (rt_data_queue_peak(&audio->replay->queue, &frame.data_ptr, &frame.data_size) == RT_EOK) - { - //pop the head frame... - rt_data_queue_pop(&audio->replay->queue, &frame.data_ptr, &frame.data_size, RT_WAITING_FOREVER); - - /* notify transmitted complete. */ - if (audio->parent.tx_complete != RT_NULL) - audio->parent.tx_complete(&audio->parent, (void *) frame.data_ptr); - } - + /* stop replay stream */ + _aduio_replay_stop(audio); 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_pipe)); - + /* stop record stream */ + _audio_record_stop(audio); dev->open_flag &= ~RT_DEVICE_OFLAG_RDONLY; } @@ -237,17 +361,19 @@ static rt_size_t _audio_dev_read(struct rt_device *dev, rt_off_t pos, void *buff 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_pipe), pos, buffer, size); + 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_uint8_t *ptr; + rt_uint16_t block_size, remain_bytes, index = 0; RT_ASSERT(dev != RT_NULL); audio = (struct rt_audio_device *) dev; @@ -255,34 +381,46 @@ static rt_size_t _audio_dev_write(struct rt_device *dev, rt_off_t pos, const voi 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 + /* push a new frame to replay data queue */ + ptr = (rt_uint8_t *)buffer; + block_size = RT_AUDIO_REPLAY_MP_BLOCK_SIZE; + + rt_mutex_take(&audio->replay->lock, RT_WAITING_FOREVER); + while (index < size) { - result = rt_data_queue_push(&audio->replay->queue, buffer, size, - RT_WAITING_FOREVER); - if (result != RT_EOK) + /* request buffer from replay memory pool */ + if (audio->replay->write_index % block_size == 0) { - AUDIO_DBG("TX frame queue push error\n"); - rt_set_errno(-RT_EFULL); - return 0; + audio->replay->write_data = rt_mp_alloc(audio->replay->mp, RT_WAITING_FOREVER); + memset(audio->replay->write_data, 0, block_size); + } + + /* copy data to replay memory pool */ + remain_bytes = MIN((block_size - audio->replay->write_index), (size - index)); + memcpy(&audio->replay->write_data[audio->replay->write_index], &ptr[index], remain_bytes); + + index += remain_bytes; + audio->replay->write_index += remain_bytes; + audio->replay->write_index %= block_size; + + if (audio->replay->write_index == 0) + { + rt_data_queue_push(&audio->replay->queue, + audio->replay->write_data, + block_size, + RT_WAITING_FOREVER); } } + rt_mutex_release(&audio->replay->lock); - //check tx state... - level = rt_hw_interrupt_disable(); + /* check replay state */ if (audio->replay->activated != RT_TRUE) { + _aduio_replay_start(audio); audio->replay->activated = RT_TRUE; - rt_hw_interrupt_enable(level); - - _audio_send_replay_frame(audio); - } - else - { - rt_hw_interrupt_enable(level); } - return size; + return index; } static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args) @@ -292,112 +430,70 @@ static rt_err_t _audio_dev_control(struct rt_device *dev, int cmd, void *args) RT_ASSERT(dev != RT_NULL); audio = (struct rt_audio_device *) dev; - //dev stat... + /* dev stat...*/ switch (cmd) { - case AUDIO_CTL_GETCAPS: - { - struct rt_audio_caps *caps = (struct rt_audio_caps *) args; + 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: + LOG_D("AUDIO_CTL_GETCAPS: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type); + if (audio->ops->getcaps != RT_NULL) { - 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); - } + result = audio->ops->getcaps(audio, caps); } break; - case AUDIO_CTL_SHUTDOWN: + } + + case AUDIO_CTL_CONFIGURE: + { + struct rt_audio_caps *caps = (struct rt_audio_caps *) args; + + LOG_D("AUDIO_CTL_CONFIGURE: main_type = %d,sub_type = %d", caps->main_type, caps->sub_type); + if (audio->ops->configure != RT_NULL) { - 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); + result = audio->ops->configure(audio, caps); } - break; - case AUDIO_CTL_START: + break; + } + + case AUDIO_CTL_START: + { + int stream = *(int *) args; + + LOG_D("AUDIO_CTL_START: stream = %d", stream); + if (stream == AUDIO_STREAM_REPLAY) { - 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); + result = _aduio_replay_start(audio); } - break; - case AUDIO_CTL_STOP: + else { - 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); - } + result = _audio_record_start(audio); } + break; - case AUDIO_CTL_PAUSE: + } + + case AUDIO_CTL_STOP: + { + int stream = *(int *) args; + + LOG_D("AUDIO_CTL_STOP: stream = %d", stream); + if (stream == AUDIO_STREAM_REPLAY) { - 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); + result = _aduio_replay_stop(audio); } - break; - case AUDIO_CTL_RESUME: + else { - 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); + result = _audio_record_stop(audio); } - break; - case AUDIO_CTL_ALLOCBUFFER: - { - struct rt_audio_buf_desc *desc = (struct rt_audio_buf_desc *) args; - if (desc) - { - desc->data_size = AUDIO_DEVICE_DECODE_MP_BLOCK_SZ * 2; - desc->data_ptr = (rt_uint8_t *)rt_mp_alloc(&audio->mp, RT_WAITING_FOREVER); + break; + } - result = RT_EOK; - } - else result = -RT_EIO; - } - break; - case AUDIO_CTL_FREEBUFFER: - { - rt_uint8_t *data_ptr = (rt_uint8_t *) args; - if (data_ptr) - rt_mp_free(data_ptr); - } - break; - default: - result = audio->ops->control(audio, cmd, args); + default: break; } @@ -418,7 +514,9 @@ const static struct rt_device_ops audio_ops = rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_uint32_t flag, void *data) { + rt_err_t result = RT_EOK; struct rt_device *device; + RT_ASSERT(audio != RT_NULL); device = &(audio->parent); @@ -438,15 +536,14 @@ rt_err_t rt_audio_register(struct rt_audio_device *audio, const char *name, rt_u #endif device->user_data = data; - //init memory pool for replay - { - rt_uint8_t *mempool = (rt_uint8_t *)rt_malloc(AUDIO_DEVICE_DECODE_MP_SZ); - rt_mp_init(&audio->mp, "adu_mp", mempool, AUDIO_DEVICE_DECODE_MP_SZ, - AUDIO_DEVICE_DECODE_MP_BLOCK_SZ * 2); - } - /* register a character device */ - return rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE); + result = rt_device_register(device, name, flag | RT_DEVICE_FLAG_REMOVABLE); + + /* initialize audio device */ + if (result == RT_EOK) + result = rt_device_init(device); + + return result; } int rt_audio_samplerate_to_speed(rt_uint32_t bitValue) @@ -454,43 +551,43 @@ int rt_audio_samplerate_to_speed(rt_uint32_t bitValue) int speed = 0; switch (bitValue) { - case AUDIO_SAMP_RATE_8K: - speed = 8000; + case AUDIO_SAMP_RATE_8K: + speed = 8000; break; - case AUDIO_SAMP_RATE_11K: - speed = 11052; + case AUDIO_SAMP_RATE_11K: + speed = 11052; break; - case AUDIO_SAMP_RATE_16K: - speed = 16000; + case AUDIO_SAMP_RATE_16K: + speed = 16000; break; - case AUDIO_SAMP_RATE_22K: - speed = 22050; + case AUDIO_SAMP_RATE_22K: + speed = 22050; break; - case AUDIO_SAMP_RATE_32K: - speed = 32000; + case AUDIO_SAMP_RATE_32K: + speed = 32000; break; - case AUDIO_SAMP_RATE_44K: - speed = 44100; + case AUDIO_SAMP_RATE_44K: + speed = 44100; break; - case AUDIO_SAMP_RATE_48K: - speed = 48000; + case AUDIO_SAMP_RATE_48K: + speed = 48000; break; - case AUDIO_SAMP_RATE_96K: - speed = 96000; + case AUDIO_SAMP_RATE_96K: + speed = 96000; break; - case AUDIO_SAMP_RATE_128K: - speed = 128000; + case AUDIO_SAMP_RATE_128K: + speed = 128000; break; - case AUDIO_SAMP_RATE_160K: - speed = 160000; + case AUDIO_SAMP_RATE_160K: + speed = 160000; break; - case AUDIO_SAMP_RATE_172K: - speed = 176400; + case AUDIO_SAMP_RATE_172K: + speed = 176400; break; - case AUDIO_SAMP_RATE_192K: - speed = 192000; + case AUDIO_SAMP_RATE_192K: + speed = 192000; break; - default: + default: break; } @@ -498,46 +595,18 @@ int rt_audio_samplerate_to_speed(rt_uint32_t bitValue) return speed; } -rt_uint32_t rt_audio_format_to_bits(rt_uint32_t format) +void rt_audio_tx_complete(struct rt_audio_device *audio) { - 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); + /* try to send next frame */ + _audio_send_replay_frame(audio); } void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len) { - //save data to record pipe - rt_device_write(RT_DEVICE(RT_DEVICE(&audio_pipe)), 0, pbuf, len); + /* save data to record pipe */ + rt_device_write(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/audio/audio_pipe.c b/components/drivers/audio/audio_pipe.c index d6975e962c..d7c37009b6 100644 --- a/components/drivers/audio/audio_pipe.c +++ b/components/drivers/audio/audio_pipe.c @@ -24,8 +24,8 @@ static void _rt_pipe_resume_writer(struct rt_audio_pipe *pipe) /* get suspended thread */ thread = rt_list_entry(pipe->suspended_write_list.next, - struct rt_thread, - tlist); + struct rt_thread, + tlist); /* resume the write thread */ rt_thread_resume(thread); @@ -66,7 +66,8 @@ static rt_size_t rt_pipe_read(rt_device_t dev, /* current context checking */ RT_DEBUG_NOT_IN_INTERRUPT; - do { + do + { level = rt_hw_interrupt_disable(); read_nbytes = rt_ringbuffer_get(&(pipe->ringbuffer), (rt_uint8_t *)buffer, size); if (read_nbytes == 0) @@ -85,7 +86,8 @@ static rt_size_t rt_pipe_read(rt_device_t dev, rt_hw_interrupt_enable(level); break; } - } while (read_nbytes == 0); + } + while (read_nbytes == 0); return read_nbytes; } @@ -104,8 +106,8 @@ static void _rt_pipe_resume_reader(struct rt_audio_pipe *pipe) /* get suspended thread */ thread = rt_list_entry(pipe->suspended_read_list.next, - struct rt_thread, - tlist); + struct rt_thread, + tlist); /* resume the read thread */ rt_thread_resume(thread); @@ -128,7 +130,7 @@ static rt_size_t rt_pipe_write(rt_device_t dev, RT_ASSERT(pipe != RT_NULL); if ((pipe->flag & RT_PIPE_FLAG_FORCE_WR) || - !(pipe->flag & RT_PIPE_FLAG_BLOCK_WR)) + !(pipe->flag & RT_PIPE_FLAG_BLOCK_WR)) { level = rt_hw_interrupt_disable(); @@ -151,7 +153,8 @@ static rt_size_t rt_pipe_write(rt_device_t dev, /* current context checking */ RT_DEBUG_NOT_IN_INTERRUPT; - do { + do + { level = rt_hw_interrupt_disable(); write_nbytes = rt_ringbuffer_put(&(pipe->ringbuffer), (const rt_uint8_t *)buffer, size); if (write_nbytes == 0) @@ -171,7 +174,8 @@ static rt_size_t rt_pipe_write(rt_device_t dev, rt_hw_interrupt_enable(level); break; } - } while (write_nbytes == 0); + } + while (write_nbytes == 0); return write_nbytes; } @@ -183,7 +187,7 @@ static rt_err_t rt_pipe_control(rt_device_t dev, int cmd, void *args) pipe = (struct rt_audio_pipe *)dev; if (cmd == PIPE_CTRL_GET_SPACE && args) - *(rt_size_t*)args = rt_ringbuffer_space_len(&pipe->ringbuffer); + *(rt_size_t *)args = rt_ringbuffer_space_len(&pipe->ringbuffer); return RT_EOK; } @@ -212,10 +216,10 @@ const static struct rt_device_ops audio_pipe_ops = * @return the operation status, RT_EOK on successful */ rt_err_t rt_audio_pipe_init(struct rt_audio_pipe *pipe, - const char *name, - rt_int32_t flag, - rt_uint8_t *buf, - rt_size_t size) + const char *name, + rt_int32_t flag, + rt_uint8_t *buf, + rt_size_t size) { RT_ASSERT(pipe); RT_ASSERT(buf); diff --git a/components/drivers/include/drivers/audio.h b/components/drivers/include/drivers/audio.h index 7d2cb36728..86057e7626 100644 --- a/components/drivers/include/drivers/audio.h +++ b/components/drivers/include/drivers/audio.h @@ -5,52 +5,30 @@ * * Change Logs: * Date Author Notes - * 2017-05-09 Urey first version + * 2017-05-09 Urey first version + * 2019-07-09 Zero-Free improve device ops interface and data flows + * */ #ifndef __AUDIO_H__ #define __AUDIO_H__ +#include "audio_pipe.h" + /* 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) - +#define AUDIO_CTL_START _AUDIO_CTL(3) +#define AUDIO_CTL_STOP _AUDIO_CTL(4) +#define AUDIO_CTL_GETBUFFERINFO _AUDIO_CTL(5) /* 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 @@ -76,13 +54,11 @@ #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 +#define AUDIO_DSP_SAMPLERATE 1 /* samplerate */ +#define AUDIO_DSP_CHANNELS 2 /* channels */ +#define AUDIO_DSP_SAMPLEBITS 3 /* sample bits width */ /* Supported Mixer Units controls */ #define AUDIO_MIXER_QUERY 0x0000 @@ -95,15 +71,13 @@ #define AUDIO_MIXER_LINE 0x0040 #define AUDIO_MIXER_DIGITAL 0x0080 #define AUDIO_MIXER_MIC 0x0100 +#define AUDIO_MIXER_VITURAL 0x0200 +#define AUDIO_MIXER_EXTEND 0x8000 /* extend mixer command */ -#define AUDIO_MIXER_EXTEND 0x8000 //extend mixer command +#define AUDIO_VOLUME_MAX (100) +#define AUDIO_VOLUME_MIN (0) #define CFG_AUDIO_REPLAY_QUEUE_COUNT 4 -#define CFG_AUDIO_RECORD_PIPE_SIZE (8 * 1024) -#define AUDIO_DEVICE_MP_CNT (4) -#define AUDIO_DEVICE_DECODE_MP_BLOCK_SZ (4352 * 4) -#define AUDIO_DEVICE_DECODE_MP_SZ ((AUDIO_DEVICE_DECODE_MP_BLOCK_SZ*2 + 4)*AUDIO_DEVICE_MP_CNT) - enum { @@ -115,19 +89,10 @@ enum /* 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_uint8_t *buffer; + rt_uint16_t block_size; + rt_uint16_t block_count; + rt_uint32_t total_size; }; struct rt_audio_device; @@ -135,73 +100,68 @@ 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, int 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 ); + 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 (*start)(struct rt_audio_device *audio, int stream); + rt_err_t (*stop)(struct rt_audio_device *audio, int stream); + 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); }; - struct rt_audio_configure { - rt_uint32_t channels; - - rt_uint32_t samplefmt; rt_uint32_t samplerate; - rt_uint32_t samplefmts; + rt_uint16_t channels; + rt_uint16_t samplebits; }; struct rt_audio_caps { - int main_type; - int sub_type; + int main_type; + int sub_type; - union - { - rt_uint32_t mask; - int value; - struct rt_audio_configure config; - }udata; + union + { + rt_uint32_t mask; + int value; + struct rt_audio_configure config; + } udata; }; struct rt_audio_replay { - rt_bool_t activated; + struct rt_mempool *mp; struct rt_data_queue queue; + struct rt_mutex lock; + struct rt_completion cmp; + struct rt_audio_buf_info buf_info; + rt_uint8_t *write_data; + rt_uint16_t write_index; + rt_uint16_t read_index; + rt_uint32_t pos; + rt_uint8_t event; + rt_bool_t activated; }; struct rt_audio_record { + struct rt_audio_pipe pipe; rt_bool_t activated; }; struct rt_audio_device { - struct rt_device parent; + struct rt_device parent; struct rt_audio_ops *ops; - - struct rt_mempool mp; - 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); - +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); +void rt_audio_rx_done(struct rt_audio_device *audio, rt_uint8_t *pbuf, rt_size_t len); /* Device Control Commands */ #define CODEC_CMD_RESET 0