Skip to content

[RFC][utest] Add audio driver test framework #10243

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
May 18, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions components/drivers/audio/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,8 @@ config RT_USING_AUDIO
config RT_AUDIO_RECORD_PIPE_SIZE
int "Record pipe size"
default 2048

config RT_UTEST_USING_AUDIO_DRIVER
bool "Enable rt_audio_api testcase"
default n
endif
5 changes: 5 additions & 0 deletions components/drivers/audio/SConscript
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,9 @@ CPPPATH = [cwd]

group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_AUDIO'], CPPPATH = CPPPATH)

list = os.listdir(cwd)
for item in list:
if os.path.isfile(os.path.join(cwd, item, 'SConscript')):
group = group + SConscript(os.path.join(item, 'SConscript'))

Return('group')
13 changes: 13 additions & 0 deletions components/drivers/audio/utest/SConscript
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Import('rtconfig')
from building import *

cwd = GetCurrentDir()
src = []
CPPPATH = [cwd]

if GetDepend('RT_UTEST_USING_ALL_CASES') or GetDepend('RT_UTEST_USING_AUDIO_DRIVER'):
src += Glob('tc_*.c')

group = DefineGroup('utestcases', src, depend = ['RT_USING_UTESTCASES', 'RT_USING_AUDIO'], CPPPATH = CPPPATH)

Return('group')
50 changes: 50 additions & 0 deletions components/drivers/audio/utest/tc_audio_common.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-05-02 wumingzi first version
*/

#include <rtthread.h>
#include <rtdevice.h>
#include <rttypes.h>
#include "utest.h"

/* DMA buffer of audio player device refresh is triggered only when the amount of transmitted data is
* greater than the size of a single block in the data queue */
#define TX_DMA_BLOCK_SIZE RT_AUDIO_REPLAY_MP_BLOCK_SIZE
#define TX_DMA_FIFO_SIZE (RT_AUDIO_REPLAY_MP_BLOCK_SIZE * 2)
#define RX_DMA_BLOCK_SIZE RT_AUDIO_RECORD_PIPE_SIZE
#define RX_DMA_FIFO_SIZE (RT_AUDIO_RECORD_PIPE_SIZE * 2)

#define SOUND_PLAYER_DEVICE_NAME "sound0"
#define SOUND_MIC_DEVICE_NAME "mic0"

#define PLAYER_SAMPLEBITS 16
#define PLAYER_SAMPLERATE 16000
#define PLAYER_CHANNEL 2
#define PLAYER_VOLUME 30

#define MIC_SAMPLEBITS 16
#define MIC_SAMPLERATE 16000
#define MIC_CHANNEL 2
#define MIC_TIME_MS 5000

extern rt_uint8_t audio_fsm_step ;

struct mic_device
{
struct rt_audio_device audio;
struct rt_audio_configure config;
rt_uint8_t *rx_fifo;
};
struct sound_device
{
struct rt_audio_device audio;
struct rt_audio_configure config;
rt_uint8_t volume;
rt_uint8_t *tx_fifo;
};
136 changes: 136 additions & 0 deletions components/drivers/audio/utest/tc_audio_drv_mic.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-05-02 wumingzi First version
*/

#include "tc_audio_common.h"

#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
#define thread_simulate_intr_create_stacksize 1024
static rt_thread_t thread_simulate_intr_handle;
static struct mic_device mic_dev;

/* Simulate callback function */
static void thread_simulate_intr(void *parameter)
{
/* Send the data(0xAA) from DMA buffer to kernel */
rt_memset((void*)&mic_dev.rx_fifo[0], 0xAA, RX_DMA_BLOCK_SIZE);
rt_audio_rx_done((struct rt_audio_device *)&(mic_dev.audio), mic_dev.rx_fifo, RX_DMA_BLOCK_SIZE);
audio_fsm_step = 1;

while (1)
{
if(audio_fsm_step == 2)
{
/* Send the the data(0x55) from DMA buffer to kernel */
rt_memset((void*)&mic_dev.rx_fifo[RX_DMA_BLOCK_SIZE], 0x55, RX_DMA_BLOCK_SIZE);
rt_audio_rx_done(&mic_dev.audio, &mic_dev.rx_fifo[RX_DMA_BLOCK_SIZE], RX_DMA_BLOCK_SIZE);
audio_fsm_step = 3;
break;
}
if(audio_fsm_step == 4)
{
rt_thread_mdelay(10);
rt_audio_rx_done(&mic_dev.audio, &mic_dev.rx_fifo[RX_DMA_BLOCK_SIZE], RX_DMA_BLOCK_SIZE);
break;
}
rt_thread_mdelay(10);
}

while(1)
{
rt_thread_mdelay(10);
}
}

static void thread_simulate_intr_create(void)
{
thread_simulate_intr_handle = rt_thread_create(
"thread_simulate_intr",
thread_simulate_intr,
RT_NULL,
thread_simulate_intr_create_stacksize,
THREAD_PRIORITY - 1, THREAD_TIMESLICE);

if (thread_simulate_intr_handle == RT_NULL)
{
rt_kprintf("Error: Failed to create thread!\n");
return;
}
if (rt_thread_startup(thread_simulate_intr_handle) != RT_EOK)
{
rt_kprintf("Error: Failed to start thread!\n");
thread_simulate_intr_handle = RT_NULL;
}

}

static rt_err_t mic_device_init(struct rt_audio_device *audio)
{
return RT_EOK;
}

/* Simulate DMA interrupt */
static rt_err_t mic_device_start(struct rt_audio_device *audio, int stream)
{
thread_simulate_intr_create();
return RT_EOK;
}

static rt_err_t mic_device_stop(struct rt_audio_device *audio, int stream)
{
if (thread_simulate_intr_handle != RT_NULL)
{
rt_thread_delete(thread_simulate_intr_handle);
thread_simulate_intr_handle = RT_NULL;
}
return RT_EOK;
}

static rt_err_t mic_device_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
return RT_EOK;
}

static rt_err_t mic_device_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
return RT_EOK;
}

static struct rt_audio_ops _mic_audio_ops =
{
.getcaps = mic_device_getcaps,
.configure = mic_device_configure,
.init = mic_device_init,
.start = mic_device_start,
.stop = mic_device_stop,
.transmit = RT_NULL,
.buffer_info = RT_NULL,
};

static int rt_hw_mic_init(void)
{
struct rt_audio_device *audio = &mic_dev.audio;
/* mic default */
mic_dev.rx_fifo = rt_malloc(RX_DMA_FIFO_SIZE);
if (mic_dev.rx_fifo == RT_NULL)
{
return -RT_ENOMEM;
}
mic_dev.config.channels = MIC_CHANNEL;
mic_dev.config.samplerate = MIC_SAMPLERATE;
mic_dev.config.samplebits = MIC_SAMPLEBITS;

/* register mic device */
audio->ops = &_mic_audio_ops;
rt_audio_register(audio, SOUND_MIC_DEVICE_NAME, RT_DEVICE_FLAG_RDONLY, (void *)&mic_dev);

return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_mic_init);
150 changes: 150 additions & 0 deletions components/drivers/audio/utest/tc_audio_drv_player.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2006-2025 RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2025-05-02 wumingzi First version
*/

#include "tc_audio_common.h"

#define THREAD_PRIORITY 9
#define THREAD_TIMESLICE 5
#define thread_simulate_intr_create_stacksize 1024
static rt_thread_t thread_simulate_intr_handle;
static struct sound_device snd_dev;

static void thread_simulate_intr(void *parameter)
{
rt_flag_t exec_once = 0;
while(1)
{
if(audio_fsm_step == 1 && exec_once == 0)
{
/* Move the data(0xAA) from kernel to DMA buffer */
rt_audio_tx_complete(&snd_dev.audio);
audio_fsm_step = 2;
exec_once = 1;
rt_thread_mdelay(10);
}
else if(audio_fsm_step == 2 && exec_once == 1)
{
/* Move the data(0x55) from kernel to DMA buffer */
rt_audio_tx_complete(&snd_dev.audio);
audio_fsm_step = 3;
rt_thread_mdelay(10);
}
else if(audio_fsm_step == 4)
{
/* rt_device_close will call rt_completion_wait(FOREVER), so we need delay to
* let system run the point */
rt_thread_mdelay(10);
rt_audio_tx_complete(&snd_dev.audio);
break;
}
rt_thread_mdelay(10);
}
while (1)
{
rt_thread_mdelay(10);
}
}

static void thread_simulate_intr_create(void)
{
thread_simulate_intr_handle = rt_thread_create(
"thread_simulate_intr",
thread_simulate_intr,
RT_NULL,
thread_simulate_intr_create_stacksize,
THREAD_PRIORITY - 1, THREAD_TIMESLICE);

rt_thread_startup(thread_simulate_intr_handle);
}

static rt_err_t player_device_init(struct rt_audio_device *audio)
{
return RT_EOK;
}

/* Simulate DMA interrupt */
static rt_err_t player_device_start(struct rt_audio_device *audio, int stream)
{
thread_simulate_intr_create();
return RT_EOK;
}

static rt_err_t player_device_stop(struct rt_audio_device *audio, int stream)
{
rt_thread_delete(thread_simulate_intr_handle);
return RT_EOK;
}

static rt_err_t player_device_getcaps(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
return RT_EOK;
}

static rt_err_t player_device_configure(struct rt_audio_device *audio, struct rt_audio_caps *caps)
{
return RT_EOK;
}

static rt_ssize_t player_device_transmit(struct rt_audio_device *audio, const void *writeBuf, void *readBuf, rt_size_t size)
{
return size;
}

static void player_device_buffer_info(struct rt_audio_device *audio, struct rt_audio_buf_info *info)
{
RT_ASSERT(audio != RT_NULL);
/**
* TX_FIFO
* +----------------+----------------+
* | block1 | block2 |
* +----------------+----------------+
* \ block_size /
*/
info->buffer = snd_dev.tx_fifo;
info->total_size = TX_DMA_FIFO_SIZE;
info->block_size = TX_DMA_BLOCK_SIZE;
info->block_count = RT_AUDIO_REPLAY_MP_BLOCK_COUNT;
}

static struct rt_audio_ops audio_ops =
{
.getcaps = player_device_getcaps,
.configure = player_device_configure,
.init = player_device_init,
.start = player_device_start,
.stop = player_device_stop,
.transmit = player_device_transmit,
.buffer_info = player_device_buffer_info,
};

static int rt_hw_sound_init(void)
{
rt_uint8_t *tx_fifo = RT_NULL;

tx_fifo = rt_malloc(TX_DMA_FIFO_SIZE);
if (tx_fifo == NULL)
{
return -RT_ENOMEM;
}
snd_dev.tx_fifo = tx_fifo;

/* Init default configuration */
{
snd_dev.config.samplerate = PLAYER_SAMPLERATE;
snd_dev.config.channels = PLAYER_CHANNEL;
snd_dev.config.samplebits = PLAYER_SAMPLEBITS;
snd_dev.volume = PLAYER_VOLUME;
}

snd_dev.audio.ops = &audio_ops;
rt_audio_register(&snd_dev.audio, SOUND_PLAYER_DEVICE_NAME, RT_DEVICE_FLAG_WRONLY, &snd_dev);
return RT_EOK;
}
INIT_DEVICE_EXPORT(rt_hw_sound_init);
Loading