#include "audio_mp3.h" #include "main.h" #include "ff.h" #include "FreeRTOS.h" #include "queue.h" #include "elog.h" #include "heap.h" #include "bsp_aic3204.h" #include "dr_mp3.h" const static char *TAG = "player_mp3"; static size_t mp3_read(void* pUserData, void* pBufferOut, size_t bytesToRead) { HAL_GPIO_TogglePin(LED_Y_GPIO_Port, LED_Y_Pin); UINT br; FRESULT f_result = f_read(pUserData, pBufferOut, bytesToRead, &br); //从文件中读取新的内容 if (f_result != FR_OK) { elog_error(TAG, "file read error"); return 0; } return br; } static drmp3_bool32 mp3_seek(void* pUserData, int offset, drmp3_seek_origin origin) { FIL *file = (FIL*)pUserData; uint32_t fptr = f_tell(file); uint32_t fsize = f_size(file); HAL_GPIO_TogglePin(LED_G_GPIO_Port, LED_G_Pin); switch (origin) { case drmp3_seek_origin_start: if (offset < fsize) { //未超过文件末尾 f_lseek(file, offset); return DRMP3_TRUE; } else { elog_warn(TAG, "flac_seek: seeking beyond the end of the file"); return DRMP3_FALSE; } case drmp3_seek_origin_current: if (fptr + offset < fsize) { //未超过文件末尾 f_lseek(file, fptr + offset); return DRMP3_TRUE; } else { elog_warn(TAG, "flac_seek: seeking beyond the end of the file"); return DRMP3_FALSE; } default: elog_warn(TAG, "flac_seek: unimplemented seek origin type: %d", origin); return DRMP3_FALSE; } } static void* mp3_malloc(size_t sz, void* pUserData) { UNUSED(pUserData); void *ptr = malloc(sz); // tlsf_pool_statistics *axi_heap_statistics = get_axi_heap_statistics(); // tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics(); // elog_debug(TAG, "mp3_malloc: allocated %d bytes memory @%p, free memory: AXI %d bytes, AHB %d bytes", // sz, ptr, axi_heap_statistics->free_size, ahb_heap_statistics->free_size); if (ptr == NULL) { elog_error(TAG, "mp3_malloc: error while allocating %d bytes of memory", sz); } return ptr; } static void* mp3_realloc(void* p, size_t sz, void* pUserData) { UNUSED(pUserData); void *ptr = realloc(p, sz); if (ptr == NULL) { elog_error(TAG, "mp3_realloc: error while allocating %d bytes of new memory", sz); } return ptr; } static void mp3_free(void* p, void* pUserData) { UNUSED(pUserData); // tlsf_pool_statistics *axi_heap_statistics = get_axi_heap_statistics(); // tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics(); // elog_debug(TAG, "mp3_free: memory freed @%p, free memory: AXI %d bytes, AHB %d bytes", // p, axi_heap_statistics->free_size, ahb_heap_statistics->free_size); free(p); } static const drmp3_allocation_callbacks mp3_allocation_cbs = { .onMalloc = mp3_malloc, .onFree = mp3_free, .onRealloc = mp3_realloc, .pUserData = NULL }; /** * @brief 播放MP3文件 * * @param file_name 文件路径 * @return esp_err_t 错误代码 * * @note 本函数需要至少25600字节任务栈空间 */ void music_mp3_play(const char *file_name) { FIL *file = malloc(sizeof(FIL)); if (file == NULL) { elog_error(TAG, "music_mp3_play: error while allocating file object"); return; } FRESULT f_result = f_open(file, file_name, FA_READ); if (f_result == FR_OK) { elog_info(TAG, "music_mp3_play: successfully opened %s for playing", file_name); } else { elog_error(TAG, "music_mp3_play: error while opening %s, error code=%d", file_name, f_result); free(file); return; } drmp3 *mp3 = malloc_dtcm(sizeof(drmp3)); //为MP3解码器分配内存 if (mp3 == NULL) { elog_error(TAG, "error while creating mp3 decoder structure"); goto exit; } drmp3_init(mp3, mp3_read, mp3_seek, file, &mp3_allocation_cbs); //初始化MP3解码器 elog_info(TAG, "music_mp3_play: channels=%d, sampleRate=%d", mp3->channels, mp3->sampleRate); /* TODO: 判断mp3文件参数并返回错误 */ bsp_aic3204_set_fs(&hi2c1, mp3->sampleRate); //设置采样率 audio_hal_start(DRMP3_MAX_SAMPLES_PER_FRAME, sizeof(drmp3_int16)); //初始化SAI while(1) { drmp3_int16 *pcm_sample = malloc(DRMP3_MAX_SAMPLES_PER_FRAME * sizeof(drmp3_int16)); if (pcm_sample == NULL) { elog_error(TAG, "music_mp3_play: sample buffer allocation failed, size=%d bytes", DRMP3_MAX_SAMPLES_PER_FRAME * sizeof(drmp3_int16)); break; } /* 此处的framesToRead指的是PCM块中采样的数量(可以理解为时间层面的采样数) 不考虑声道数量与每个采样的字节数 */ uint32_t sample_count = drmp3_read_pcm_frames_s16(mp3, DRMP3_MAX_PCM_FRAMES_PER_MP3_FRAME, pcm_sample); //解码新一帧MP3数据 if (sample_count != 0) { audio_hal_write(pcm_sample, DRMP3_MAX_SAMPLES_PER_FRAME * sizeof(drmp3_int16)); ///将解码后的PCM数据写入SAI } else { free(pcm_sample); elog_info(TAG, "play done"); break; //结束播放 } if (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) { vTaskDelay(pdMS_TO_TICKS(100)); while (HAL_GPIO_ReadPin(KEY2_GPIO_Port, KEY2_Pin) == GPIO_PIN_RESET) { vTaskDelay(pdMS_TO_TICKS(1)); } break; } } exit: audio_hal_stop(); //停止SAI播放 if (file != NULL) { f_close(file); //关闭文件 free(file); } if (mp3 != NULL) { //释放为解码器分配的内存 drmp3_uninit(mp3); free_dtcm(mp3); } }