#include "audio_player_mp3.h"
#include <stdio.h>
#include "main.h"
#include "ff.h"
#include "FreeRTOS.h"
#include "queue.h"
#include "elog.h"
#include "heap.h"
#include "bsp_aic3204.h"

#define MINIMP3_IMPLEMENTATION
#include "minimp3.h"

const static char *TAG = "player_mp3";

/**
 * @brief 播放MP3文件
 *
 * @param file_name 文件路径
 * @return esp_err_t 错误代码
 *
 * @note 本函数需要至少25600字节任务栈空间
 */
void music_mp3_play(const char *file_name)
{
  FIL *file = malloc(sizeof(FIL));
  uint8_t *file_buffer = malloc(FILE_BUFFER_SIZE);

  FRESULT f_result = f_open(file, file_name, FA_READ);
  if (f_result == FR_OK) {
    elog_info(TAG, "open %s successful", file_name);
  } else {
    elog_error(TAG, "open %s failed, error code: %d", file_name, f_result);
    return;
  }

  /* 创建并初始化解码器 */
  mp3dec_t mp3d; //6668 bytes
  mp3dec_init(&mp3d);
  /* 初始化SAI */
  audio_hal_start(MINIMP3_MAX_SAMPLES_PER_FRAME, sizeof(mp3d_sample_t));

  int32_t file_buffer_available = 0; //剩余的缓冲区大小
  while(1) {
    /* 从文件中补充数据到缓冲区 */
    if(file_buffer_available < FILE_BUFFER_SIZE/2) { //文件缓冲区剩余不足一半
      int32_t file_buffer_consumed = (FILE_BUFFER_SIZE - file_buffer_available);
      UINT br;

      f_result = f_read(file, file_buffer+file_buffer_available, file_buffer_consumed, &br); //从文件中读取新的内容
      if (f_result != FR_OK) {
        elog_error(TAG, "file read error");
        break;
      }
      file_buffer_available += br;

      // uint32_t bytes_read = file_buffer_consumed + file_buffer_available - FILE_BUFFER_SIZE;
      // if (bytes_read > 0) {
      //   elog_verbose(TAG, "reading %d bytes from file", (int)bytes_read);
      // }
      HAL_GPIO_TogglePin(LED_Y_GPIO_Port, LED_Y_Pin);

      if(file_buffer_available <= 0) { //文件已经读取完毕
        elog_info(TAG, "play done");
        break; //结束播放
      }
    }

    /* 解码新一帧MP3数据 */
    mp3dec_frame_info_t info;
    mp3d_sample_t *sample = malloc(MINIMP3_MAX_SAMPLES_PER_FRAME * sizeof(mp3d_sample_t));
    uint32_t sample_count = mp3dec_decode_frame(&mp3d, file_buffer, file_buffer_available, sample, &info);
    /* 将解码后的PCM数据写入SAI */
    if (sample_count != 0) {
      audio_hal_write(sample, sample_count * 2 * sizeof(mp3d_sample_t)); //sample_count只包含一个声道的采样数
    } else {
      free(sample);
    }
    /* 从缓冲区中删除解码完毕的帧 */
    file_buffer_available -= info.frame_bytes; //从剩余缓冲区大小中减去被消耗的缓冲区大小
    memmove(file_buffer, file_buffer+info.frame_bytes, file_buffer_available); //删除已消耗的缓冲区内容

    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;
    }

    if (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
      vTaskDelay(pdMS_TO_TICKS(100));
      static uint8_t samplerate = 0;

      switch (samplerate) {
      case 0:
        bsp_aic3204_set_fs(&hi2c1, 8000);
        break;
      case 1:
        bsp_aic3204_set_fs(&hi2c1, 11025);
        break;
      case 2:
        bsp_aic3204_set_fs(&hi2c1, 12000);
        break;
      case 3:
        bsp_aic3204_set_fs(&hi2c1, 16000);
        break;
      case 4:
        bsp_aic3204_set_fs(&hi2c1, 22050);
        break;
      case 5:
        bsp_aic3204_set_fs(&hi2c1, 24000);
        break;
      case 6:
        bsp_aic3204_set_fs(&hi2c1, 32000);
        break;
      case 7:
        bsp_aic3204_set_fs(&hi2c1, 44100);
        break;
      case 8:
        bsp_aic3204_set_fs(&hi2c1, 48000);
        break;
      case 9:
        bsp_aic3204_set_fs(&hi2c1, 88200);
        break;
      case 10:
        bsp_aic3204_set_fs(&hi2c1, 96000);
        break;
      case 11:
        bsp_aic3204_set_fs(&hi2c1, 176400);
        break;
      case 12:
        bsp_aic3204_set_fs(&hi2c1, 192000);
        break;
      }

      samplerate ++;
      if (samplerate >= 13) {
        samplerate = 0;
      }

      while (HAL_GPIO_ReadPin(KEY1_GPIO_Port, KEY1_Pin) == GPIO_PIN_RESET) {
        vTaskDelay(pdMS_TO_TICKS(1));
      }
    }
  }

  /* 关闭文件 */
  audio_hal_stop();
  f_close(file);
  free(file_buffer);
  free(file);

  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);
}
