修复flac播放问题
This commit is contained in:
parent
ceb750efe4
commit
ace169decb
@ -5,6 +5,7 @@
|
||||
#include "queue.h"
|
||||
#include "elog.h"
|
||||
#include "heap.h"
|
||||
#include "bsp_aic3204.h"
|
||||
|
||||
#define DR_FLAC_NO_STDIO
|
||||
#define DR_FLAC_NO_OGG
|
||||
@ -21,8 +22,6 @@ static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead)
|
||||
UINT br;
|
||||
FRESULT f_result = f_read(pUserData, pBufferOut, bytesToRead, &br); //从文件中读取新的内容
|
||||
|
||||
// elog_verbose(TAG, "flac_read: reading %d bytes, %d bytes read", bytesToRead, br);
|
||||
|
||||
if (f_result != FR_OK) {
|
||||
elog_error(TAG, "file read error");
|
||||
return 0;
|
||||
@ -34,52 +33,67 @@ static size_t flac_read(void* pUserData, void* pBufferOut, size_t bytesToRead)
|
||||
static drflac_bool32 flac_seek(void* pUserData, int offset, drflac_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);
|
||||
|
||||
if (origin == drflac_seek_origin_start) {
|
||||
f_lseek(file, offset);
|
||||
elog_debug(TAG, "flac_seek: drflac_seek_origin_start, offset=%d, fptr=%d", offset, f_tell(file));
|
||||
} else {
|
||||
uint32_t fptr = f_tell(file);
|
||||
if (fptr + offset > f_size(file)) {
|
||||
switch (origin) {
|
||||
case drflac_seek_origin_start:
|
||||
if (offset < fsize) { //未超过文件末尾
|
||||
f_lseek(file, offset);
|
||||
return DRFLAC_TRUE;
|
||||
} else {
|
||||
elog_warn(TAG, "flac_seek: seeking beyond the end of the file");
|
||||
return false;
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
case drflac_seek_origin_current:
|
||||
if (fptr + offset < fsize) { //未超过文件末尾
|
||||
f_lseek(file, fptr + offset);
|
||||
return DRFLAC_TRUE;
|
||||
} else {
|
||||
elog_warn(TAG, "flac_seek: seeking beyond the end of the file");
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
f_lseek(file, fptr + offset);
|
||||
elog_debug(TAG, "flac_seek: drflac_seek_origin_current, offset=%d, fptr original=%d, fptr=%d", offset, fptr, f_tell((FIL*)pUserData));
|
||||
}
|
||||
|
||||
return true;
|
||||
default:
|
||||
elog_warn(TAG, "flac_seek: unimplemented seek origin type: %d", origin);
|
||||
return DRFLAC_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
void* flac_malloc(size_t sz, void* pUserData)
|
||||
static void* flac_malloc(size_t sz, void* pUserData)
|
||||
{
|
||||
UNUSED(pUserData);
|
||||
|
||||
void *ptr = malloc(sz);
|
||||
|
||||
elog_warn(TAG, "flac_malloc: %d bytes", sz);
|
||||
tlsf_pool_statistics *dtcm_heap_statistics = get_dtcm_heap_statistics();
|
||||
tlsf_pool_statistics *axi_heap_statistics = get_axi_heap_statistics();
|
||||
tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics();
|
||||
elog_verbose(TAG, "free heap: DTCM: %d, AXI: %d", dtcm_heap_statistics->free_size, ahb_heap_statistics->free_size);
|
||||
elog_debug(TAG, "flac_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);
|
||||
|
||||
return ptr;
|
||||
}
|
||||
void* flac_realloc(void* p, size_t sz, void* pUserData)
|
||||
|
||||
static void* flac_realloc(void* p, size_t sz, void* pUserData)
|
||||
{
|
||||
UNUSED(pUserData);
|
||||
|
||||
void *ptr = realloc(p, sz);
|
||||
|
||||
elog_warn(TAG, "flac_realloc: %d bytes", sz);
|
||||
return ptr;
|
||||
}
|
||||
|
||||
void flac_free(void* p, void* pUserData)
|
||||
static void flac_free(void* p, void* pUserData)
|
||||
{
|
||||
UNUSED(pUserData);
|
||||
|
||||
elog_warn(TAG, "flac_free");
|
||||
tlsf_pool_statistics *axi_heap_statistics = get_axi_heap_statistics();
|
||||
tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics();
|
||||
elog_debug(TAG, "flac_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);
|
||||
}
|
||||
|
||||
@ -90,11 +104,6 @@ static const drflac_allocation_callbacks callbacks = {
|
||||
.pUserData = NULL
|
||||
};
|
||||
|
||||
// static void flac_on_meta(void* pUserData, drflac_metadata* pMetadata)
|
||||
// {
|
||||
// elog_warn(TAG, "on metadata %d", pMetadata->type);
|
||||
// }
|
||||
|
||||
void music_flac_play(const char *file_name)
|
||||
{
|
||||
FIL *file = malloc(sizeof(FIL));
|
||||
@ -113,52 +122,61 @@ void music_flac_play(const char *file_name)
|
||||
}
|
||||
|
||||
/* 创建并初始化解码器 */
|
||||
// drflac* pFlac = drflac_open_with_metadata(flac_read, flac_seek, flac_on_meta, file, NULL);
|
||||
drflac* pFlac = drflac_open(flac_read, flac_seek, file, &callbacks);
|
||||
if (pFlac == NULL) {
|
||||
elog_error(TAG, "error while creating opening flac file");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
/* 初始化SAI */
|
||||
uint32_t pcm_sample_count = pFlac->maxBlockSizeInPCMFrames * pFlac->channels; //每一个PCM块的采样数量
|
||||
audio_hal_start(pcm_sample_count, pFlac->bitsPerSample / 8);
|
||||
|
||||
elog_info(TAG, "music_flac_play: maxBlockSizeInPCMFrames=%d, channels=%d, bitsPerSample=%d",
|
||||
pFlac->maxBlockSizeInPCMFrames, pFlac->channels, pFlac->bitsPerSample);
|
||||
|
||||
/* TODO: 判断flac文件参数并返回错误 */
|
||||
|
||||
bsp_aic3204_set_fs(&hi2c1, pFlac->sampleRate); //设置采样率
|
||||
|
||||
/* 初始化SAI */
|
||||
uint32_t pcm_sample_count = pFlac->maxBlockSizeInPCMFrames * pFlac->channels; //PCM块中所有声道总的采样数量
|
||||
uint32_t pcm_sample_size = pFlac->bitsPerSample / 8; //PCM块中每个采样的字节数(采样精度)
|
||||
audio_hal_start(pcm_sample_count, pcm_sample_size);
|
||||
|
||||
while(1) {
|
||||
drflac_int16 *sample = malloc(pcm_sample_count * (pFlac->bitsPerSample / 8));
|
||||
if (sample == NULL) {
|
||||
elog_error(TAG, "%d bytes memory allocation failed", pcm_sample_count * (pFlac->bitsPerSample / 8));
|
||||
/* 如果当前是最后一个frame 则frame_count可能小于maxBlockSizeInPCMFrames 因此需要将pcm_sample初始化为全0 将空白区域静音 */
|
||||
drflac_int16 *pcm_sample = malloc(pcm_sample_count * pcm_sample_size); //申请内存 存储1个PCM块
|
||||
if (pcm_sample == NULL) {
|
||||
elog_error(TAG, "memory allocation failed, size=%d bytes", pcm_sample_count * pcm_sample_size);
|
||||
break;
|
||||
}
|
||||
/* 解码新一帧FLAC数据 */
|
||||
uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, pFlac->maxBlockSizeInPCMFrames, sample);
|
||||
memset(pcm_sample, 0, pcm_sample_count * pcm_sample_size);
|
||||
|
||||
/* 此处的framesToRead指的是PCM块中采样的数量(可以理解为时间层面的采样数) 不考虑声道数量与每个采样的字节数 */
|
||||
uint32_t frame_count = drflac_read_pcm_frames_s16(pFlac, pFlac->maxBlockSizeInPCMFrames, pcm_sample); //解码一帧FLAC数据
|
||||
|
||||
/* 将解码后的PCM数据写入SAI */
|
||||
if (frame_count != 0) {
|
||||
elog_verbose(TAG, "writing %d bytes of pcm data", frame_count * sizeof(drflac_int16));
|
||||
audio_hal_write(sample, pcm_sample_count * pFlac->channels);
|
||||
/* 即使frame_count小于maxBlockSizeInPCMFrames也写入完整的一块 缓冲区后面空缺的部分在前面已经清0 */
|
||||
audio_hal_write(pcm_sample, pcm_sample_count * pcm_sample_size); //将解码后的PCM数据写入SAI
|
||||
} else { //文件已经读取完毕
|
||||
free(sample);
|
||||
free(pcm_sample);
|
||||
elog_info(TAG, "play done");
|
||||
break; //结束播放
|
||||
}
|
||||
}
|
||||
|
||||
/* 关闭文件 */
|
||||
f_close(file);
|
||||
free(file);
|
||||
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();
|
||||
audio_hal_stop(); //停止SAI播放
|
||||
|
||||
if (pFlac) {
|
||||
f_close(file); //关闭文件
|
||||
free(file);
|
||||
|
||||
if (pFlac) { //释放解码器
|
||||
drflac_close(pFlac);
|
||||
}
|
||||
|
||||
tlsf_pool_statistics *dtcm_heap_statistics = get_dtcm_heap_statistics();
|
||||
tlsf_pool_statistics *ahb_heap_statistics = get_ahb_heap_statistics();
|
||||
elog_verbose(TAG, "free heap: DTCM: %d, AXI: %d", dtcm_heap_statistics->free_size, ahb_heap_statistics->free_size);
|
||||
}
|
||||
|
||||
@ -16,6 +16,7 @@ typedef struct {
|
||||
static QueueHandle_t audio_queue = NULL;
|
||||
static uint8_t *audio_buffer = NULL;
|
||||
static uint32_t audio_buffer_length = 0;
|
||||
static uint8_t audio_buffer_underrun_warn_flag = 0;
|
||||
|
||||
void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
|
||||
{
|
||||
@ -63,6 +64,7 @@ void audio_hal_start(uint32_t sample_count, uint8_t sample_size)
|
||||
vQueueDelete(audio_queue);
|
||||
}
|
||||
audio_queue = xQueueCreate(AUDIO_HAL_SAMPLE_QUEUE_SIZE, sizeof(audio_sample_t));
|
||||
audio_buffer_underrun_warn_flag = 0;
|
||||
|
||||
HAL_SAI_Transmit_DMA(&hsai_BlockB1, audio_buffer, sample_count * 2); //开始DMA循环发送
|
||||
}
|
||||
@ -71,6 +73,12 @@ void audio_hal_stop(void)
|
||||
{
|
||||
HAL_SAI_DMAStop(&hsai_BlockB1);
|
||||
|
||||
audio_sample_t sample;
|
||||
while (xQueueReceive(audio_queue, &sample, 0) == pdTRUE) {
|
||||
free(sample.buffer_ptr);
|
||||
elog_debug(TAG, "audio_hal_stop: freeing unused buffer");
|
||||
}
|
||||
|
||||
vQueueDelete(audio_queue);
|
||||
audio_queue = NULL;
|
||||
|
||||
@ -89,9 +97,10 @@ void audio_hal_write(void *buffer_ptr, uint32_t buffer_size)
|
||||
.buffer_size = buffer_size
|
||||
};
|
||||
|
||||
if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE) {
|
||||
elog_warn(TAG, "audio_hal_write: queue is empty before xQueueSend");
|
||||
if (uxQueueSpacesAvailable(audio_queue) == AUDIO_HAL_SAMPLE_QUEUE_SIZE && audio_buffer_underrun_warn_flag != 0) {
|
||||
elog_warn(TAG, "audio_hal_write: audio sample queue is empty before xQueueSend");
|
||||
}
|
||||
|
||||
xQueueSend(audio_queue, &sample, portMAX_DELAY); //发送缓冲区到队列中
|
||||
audio_buffer_underrun_warn_flag = 1; //屏蔽首次报错
|
||||
}
|
||||
|
||||
@ -152,11 +152,11 @@ void task_main_entry(void *param)
|
||||
util_i2c_scan(&hi2c1);
|
||||
|
||||
while (1) {
|
||||
music_flac_play("HOYO-MiX - Village Surrounded by Green 葳蕤林野间.flac");
|
||||
music_flac_play("四季音色 - 斑光.flac");
|
||||
music_flac_play("唐九夏 - 一克拉月光.flac");
|
||||
music_mp3_play("夏川椎菜 - No.1.mp3");
|
||||
music_mp3_play("HoneyWorks,早見沙織 - 可愛くてごめん.mp3");
|
||||
music_mp3_play("堀江由衣 - silky heart.mp3");
|
||||
music_mp3_play("倉木麻衣 - Time after time〜花舞う街で〜.mp3");
|
||||
music_mp3_play("Candy_Wind - Go For The Next !.mp3");
|
||||
music_mp3_play("July - Somewhere.mp3");
|
||||
music_mp3_play("Wiz Khalifa; Charlie Puth - See You Again.mp3");
|
||||
|
||||
Loading…
Reference in New Issue
Block a user