Initial public release of the 2024A software.
This commit is contained in:
parent
7b9ad3edfd
commit
303e9e1dad
361 changed files with 60083 additions and 2 deletions
|
@ -0,0 +1,4 @@
|
|||
idf_component_register(SRC_DIRS "."
|
||||
PRIV_INCLUDE_DIRS "."
|
||||
PRIV_REQUIRES unity test_utils audio_player
|
||||
EMBED_TXTFILES gs-16b-1c-44100hz.mp3)
|
|
@ -0,0 +1,282 @@
|
|||
// Copyright 2020 Espressif Systems (Shanghai) Co. Ltd.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
#include "esp_log.h"
|
||||
#include "esp_check.h"
|
||||
#include "unity.h"
|
||||
#include "audio_player.h"
|
||||
#include "driver/gpio.h"
|
||||
#include "test_utils.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
static const char *TAG = "AUDIO PLAYER TEST";
|
||||
|
||||
#define CONFIG_BSP_I2S_NUM 1
|
||||
|
||||
/* Audio */
|
||||
#define BSP_I2S_SCLK (GPIO_NUM_17)
|
||||
#define BSP_I2S_MCLK (GPIO_NUM_2)
|
||||
#define BSP_I2S_LCLK (GPIO_NUM_47)
|
||||
#define BSP_I2S_DOUT (GPIO_NUM_15) // To Codec ES8311
|
||||
#define BSP_I2S_DSIN (GPIO_NUM_16) // From ADC ES7210
|
||||
#define BSP_POWER_AMP_IO (GPIO_NUM_46)
|
||||
#define BSP_MUTE_STATUS (GPIO_NUM_1)
|
||||
|
||||
/**
|
||||
* @brief ESP-BOX I2S pinout
|
||||
*
|
||||
* Can be used for i2s_std_gpio_config_t and/or i2s_std_config_t initialization
|
||||
*/
|
||||
#define BSP_I2S_GPIO_CFG \
|
||||
{ \
|
||||
.mclk = BSP_I2S_MCLK, \
|
||||
.bclk = BSP_I2S_SCLK, \
|
||||
.ws = BSP_I2S_LCLK, \
|
||||
.dout = BSP_I2S_DOUT, \
|
||||
.din = BSP_I2S_DSIN, \
|
||||
.invert_flags = { \
|
||||
.mclk_inv = false, \
|
||||
.bclk_inv = false, \
|
||||
.ws_inv = false, \
|
||||
}, \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Mono Duplex I2S configuration structure
|
||||
*
|
||||
* This configuration is used by default in bsp_audio_init()
|
||||
*/
|
||||
#define BSP_I2S_DUPLEX_MONO_CFG(_sample_rate) \
|
||||
{ \
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(_sample_rate), \
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO), \
|
||||
.gpio_cfg = BSP_I2S_GPIO_CFG, \
|
||||
}
|
||||
|
||||
static i2s_chan_handle_t i2s_tx_chan;
|
||||
static i2s_chan_handle_t i2s_rx_chan;
|
||||
|
||||
static esp_err_t bsp_i2s_write(void * audio_buffer, size_t len, size_t *bytes_written, uint32_t timeout_ms)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
ret = i2s_channel_write(i2s_tx_chan, (char *)audio_buffer, len, bytes_written, timeout_ms);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t bsp_i2s_reconfig_clk(uint32_t rate, uint32_t bits_cfg, i2s_slot_mode_t ch)
|
||||
{
|
||||
esp_err_t ret = ESP_OK;
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(rate),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG((i2s_data_bit_width_t)bits_cfg, (i2s_slot_mode_t)ch),
|
||||
.gpio_cfg = BSP_I2S_GPIO_CFG,
|
||||
};
|
||||
|
||||
ret |= i2s_channel_disable(i2s_tx_chan);
|
||||
ret |= i2s_channel_reconfig_std_clock(i2s_tx_chan, &std_cfg.clk_cfg);
|
||||
ret |= i2s_channel_reconfig_std_slot(i2s_tx_chan, &std_cfg.slot_cfg);
|
||||
ret |= i2s_channel_enable(i2s_tx_chan);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static esp_err_t audio_mute_function(AUDIO_PLAYER_MUTE_SETTING setting) {
|
||||
ESP_LOGI(TAG, "mute setting %d", setting);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
TEST_CASE("audio player can be newed and deleted", "[audio player]")
|
||||
{
|
||||
audio_player_config_t config = { .mute_fn = audio_mute_function,
|
||||
.write_fn = bsp_i2s_write,
|
||||
.clk_set_fn = bsp_i2s_reconfig_clk,
|
||||
.priority = 0,
|
||||
.coreID = 0 };
|
||||
esp_err_t ret = audio_player_new(config);
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
ret = audio_player_delete();
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
audio_player_state_t state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_SHUTDOWN);
|
||||
}
|
||||
|
||||
static esp_err_t bsp_audio_init(const i2s_std_config_t *i2s_config, i2s_chan_handle_t *tx_channel, i2s_chan_handle_t *rx_channel)
|
||||
{
|
||||
/* Setup I2S peripheral */
|
||||
i2s_chan_config_t chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(CONFIG_BSP_I2S_NUM, I2S_ROLE_MASTER);
|
||||
chan_cfg.auto_clear = true; // Auto clear the legacy data in the DMA buffer
|
||||
ESP_ERROR_CHECK(i2s_new_channel(&chan_cfg, tx_channel, rx_channel));
|
||||
|
||||
/* Setup I2S channels */
|
||||
const i2s_std_config_t std_cfg_default = BSP_I2S_DUPLEX_MONO_CFG(22050);
|
||||
const i2s_std_config_t *p_i2s_cfg = &std_cfg_default;
|
||||
if (i2s_config != NULL) {
|
||||
p_i2s_cfg = i2s_config;
|
||||
}
|
||||
|
||||
if (tx_channel != NULL) {
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(*tx_channel, p_i2s_cfg));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(*tx_channel));
|
||||
}
|
||||
if (rx_channel != NULL) {
|
||||
ESP_ERROR_CHECK(i2s_channel_init_std_mode(*rx_channel, p_i2s_cfg));
|
||||
ESP_ERROR_CHECK(i2s_channel_enable(*rx_channel));
|
||||
}
|
||||
|
||||
/* Setup power amplifier pin */
|
||||
const gpio_config_t io_conf = {
|
||||
.intr_type = GPIO_INTR_DISABLE,
|
||||
.mode = GPIO_MODE_OUTPUT,
|
||||
.pin_bit_mask = BIT64(BSP_POWER_AMP_IO),
|
||||
.pull_down_en = GPIO_PULLDOWN_DISABLE,
|
||||
.pull_up_en = GPIO_PULLDOWN_DISABLE,
|
||||
};
|
||||
ESP_ERROR_CHECK(gpio_config(&io_conf));
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
static audio_player_callback_event_t expected_event;
|
||||
static QueueHandle_t event_queue;
|
||||
|
||||
static void audio_player_callback(audio_player_cb_ctx_t *ctx)
|
||||
{
|
||||
TEST_ASSERT_EQUAL(ctx->audio_event, expected_event);
|
||||
|
||||
// wake up the test so it can continue to the next step
|
||||
TEST_ASSERT_EQUAL(xQueueSend(event_queue, &(ctx->audio_event), 0), pdPASS);
|
||||
}
|
||||
|
||||
TEST_CASE("audio player states and callbacks are correct", "[audio player]")
|
||||
{
|
||||
audio_player_callback_event_t event;
|
||||
|
||||
/* Configure I2S peripheral and Power Amplifier */
|
||||
i2s_std_config_t std_cfg = {
|
||||
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(44100),
|
||||
.slot_cfg = I2S_STD_PHILIP_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_STEREO),
|
||||
.gpio_cfg = BSP_I2S_GPIO_CFG,
|
||||
};
|
||||
esp_err_t ret = bsp_audio_init(&std_cfg, &i2s_tx_chan, &i2s_rx_chan);
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
audio_player_config_t config = { .mute_fn = audio_mute_function,
|
||||
.write_fn = bsp_i2s_write,
|
||||
.clk_set_fn = bsp_i2s_reconfig_clk,
|
||||
.priority = 0,
|
||||
.coreID = 0 };
|
||||
ret = audio_player_new(config);
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
event_queue = xQueueCreate(1, sizeof(audio_player_callback_event_t));
|
||||
TEST_ASSERT_NOT_NULL(event_queue);
|
||||
|
||||
ret = audio_player_callback_register(audio_player_callback, NULL);
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
audio_player_state_t state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_IDLE);
|
||||
|
||||
extern const char mp3_start[] asm("_binary_gs_16b_1c_44100hz_mp3_start");
|
||||
extern const char mp3_end[] asm("_binary_gs_16b_1c_44100hz_mp3_end");
|
||||
|
||||
// -1 due to the size being 1 byte too large, I think because end is the byte
|
||||
// immediately after the last byte in the memory but I'm not sure - cmm 2022-08-20
|
||||
//
|
||||
// Suppression as these are linker symbols and cppcheck doesn't know how to ensure
|
||||
// they are the same object
|
||||
// cppcheck-suppress comparePointers
|
||||
size_t mp3_size = (mp3_end - mp3_start) - 1;
|
||||
ESP_LOGI(TAG, "mp3_size %zu bytes", mp3_size);
|
||||
|
||||
FILE *fp = fmemopen((void*)mp3_start, mp3_size, "rb");
|
||||
TEST_ASSERT_NOT_NULL(fp);
|
||||
|
||||
|
||||
|
||||
///////////////
|
||||
expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PLAYING;
|
||||
ret = audio_player_play(fp);
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
// wait for playing event to arrive
|
||||
TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS);
|
||||
|
||||
// confirm state is playing
|
||||
state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_PLAYING);
|
||||
|
||||
|
||||
|
||||
///////////////
|
||||
expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PAUSE;
|
||||
ret = audio_player_pause();
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
// wait for paused event to arrive
|
||||
TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS);
|
||||
|
||||
state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_PAUSE);
|
||||
|
||||
|
||||
|
||||
////////////////
|
||||
expected_event = AUDIO_PLAYER_CALLBACK_EVENT_PLAYING;
|
||||
ret = audio_player_resume();
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
// wait for paused event to arrive
|
||||
TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS);
|
||||
|
||||
|
||||
|
||||
///////////////
|
||||
expected_event = AUDIO_PLAYER_CALLBACK_EVENT_IDLE;
|
||||
|
||||
// the track is 16 seconds long so lets wait a bit here
|
||||
int sleep_seconds = 16;
|
||||
ESP_LOGI(TAG, "sleeping for %d seconds for playback to complete", sleep_seconds);
|
||||
vTaskDelay(pdMS_TO_TICKS(sleep_seconds * 1000));
|
||||
|
||||
// wait for idle event to arrive
|
||||
TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS);
|
||||
|
||||
state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_IDLE);
|
||||
|
||||
|
||||
|
||||
///////////////
|
||||
expected_event = AUDIO_PLAYER_CALLBACK_EVENT_SHUTDOWN;
|
||||
ret = audio_player_delete();
|
||||
TEST_ASSERT_EQUAL(ret, ESP_OK);
|
||||
|
||||
// wait for idle event to arrive
|
||||
TEST_ASSERT_EQUAL(xQueueReceive(event_queue, &event, pdMS_TO_TICKS(100)), pdPASS);
|
||||
|
||||
state = audio_player_get_state();
|
||||
TEST_ASSERT_EQUAL(state, AUDIO_PLAYER_STATE_SHUTDOWN);
|
||||
|
||||
vQueueDelete(event_queue);
|
||||
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_tx_chan));
|
||||
TEST_ESP_OK(i2s_channel_disable(i2s_rx_chan));
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_tx_chan));
|
||||
TEST_ESP_OK(i2s_del_channel(i2s_rx_chan));
|
||||
|
||||
ESP_LOGI(TAG, "NOTE: a memory leak will be reported the first time this test runs.\n");
|
||||
ESP_LOGI(TAG, "esp-idf v4.4.1 and v4.4.2 both leak memory between i2s_driver_install() and i2s_driver_uninstall()\n");
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
#
|
||||
#Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_ADD_LDFLAGS = -Wl,--whole-archive -l$(COMPONENT_NAME) -Wl,--no-whole-archive
|
||||
COMPONENT_EMBED_TXTFILES += gs-16b-1c-44100hz.mp3
|
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue