text: #include <k_api.h>
  #include "audio.h"
  #include "stm32l4xx_hal.h"
  #include "soc_init.h"
  #include "aos/hal/flash.h"
  #include "aos/vfs.h"
  #include <fcntl.h>
  
  /* #define FLASH_MONO_DATA */
  
  #define PART_FOR_AUDIO            HAL_PARTITION_OTA_TEMP
  #define HANDLE_SAI                hsai_BlockA2
  #define HANDLE_DMA                hdma_sai2_a
  
  typedef enum {
      SAI_dir_tx_m2p,
      SAI_dir_rx_p2m
  } SAI_DIRECTION;
  
  #define SAMPLE_RATE               8000
  #define SAI_DATASIZE              16
  #define SAI_DATA_BYTES            (SAI_DATASIZE / 8)
  #define DATA_BUFF_LEN             ((16 << 10) / SAI_DATA_BYTES)
  
  /* in millisecond */
  #define DMA_WAIT_TIMEOUT          8000
  #define SAI_WAIT_TIMEOUT          1000
  
  #define MAX_SIZE_PATH             256
  #define SDCARD_AUDIO_DIR          "/sdcard/devkit_audio"
  
  #if (SAI_DATASIZE == 8)
  typedef uint8_t SAI_datatype;
  #elif (SAI_DATASIZE == 16)
  typedef uint16_t SAI_datatype;
  #elif (SAI_DATASIZE == 32)
  typedef uint32_t SAI_datatype;
  #else
  #error "Invalid sai datasize!"
  #endif
  
  static SAI_datatype data_buff[DATA_BUFF_LEN] = {0};
  static __IO int16_t UpdatePointer = -1;
  static aos_mutex_t sai_mutex;
  static aos_sem_t audio_sem;
  
  extern SAI_HandleTypeDef HANDLE_SAI;
  extern DMA_HandleTypeDef HANDLE_DMA;
  
  static uint32_t get_audio_part_len(void)
  {
      hal_logic_partition_t audio_part;
      int32_t ret = 0;
  
      ret = hal_flash_info_get(PART_FOR_AUDIO, &audio_part);
  
      if (ret != 0) {
          return 0;
      }
  
      return audio_part.partition_length;
  }
  
  static float get_run_time(void)
  {
      float time_in_sec = 0.0;
  
  #ifdef FLASH_MONO_DATA
      time_in_sec = get_audio_part_len() / (SAMPLE_RATE * SAI_DATA_BYTES);
  #else
      time_in_sec = get_audio_part_len() / (SAMPLE_RATE * SAI_DATA_BYTES * 2);
  #endif
  
      return time_in_sec;
  }
  
  static int reinit_sai_and_dma(SAI_DIRECTION dir)
  {
      static SAI_DIRECTION sai_dma_status = SAI_dir_rx_p2m;
  
      if (dir == sai_dma_status)
          return 0;
  
      switch (dir) {
          case SAI_dir_tx_m2p:
              hal_gpio_output_high(&brd_gpio_table[GPIO_AUDIO_CTL]);
              break;
          case SAI_dir_rx_p2m:
              hal_gpio_output_low(&brd_gpio_table[GPIO_AUDIO_CTL]);
              break;
          default:
              KIDS_A10_PRT("Parameters is invalied, dir: %d\n", dir);
              return -1;
      }
  
      HANDLE_SAI.Init.AudioMode = (dir == SAI_dir_tx_m2p ? SAI_MODESLAVE_TX : SAI_MODESLAVE_RX);
      HANDLE_SAI.Init.ClockStrobing = (dir == SAI_dir_tx_m2p ? SAI_CLOCKSTROBING_FALLINGEDGE : SAI_CLOCKSTROBING_RISINGEDGE);
      if (HAL_SAI_Init(&HANDLE_SAI) != HAL_OK)
      {
          KIDS_A10_PRT("HAL_SAI_Init return failed.\n");
          return -1;
      }
  
      HANDLE_DMA.Init.Direction = (dir == SAI_dir_tx_m2p ? DMA_MEMORY_TO_PERIPH : DMA_PERIPH_TO_MEMORY);
      if (HAL_DMA_Init(&HANDLE_DMA) != HAL_OK)
      {
          KIDS_A10_PRT("HAL_DMA_Init return failed.\n");
          return -1;
      }
      sai_dma_status = dir;
  
      return 0;
  }
  
  /* stereo to mono */
  static void ready_to_save(SAI_datatype *data, uint32_t data_num)
  {
      uint32_t i;
      uint32_t frame_num = data_num / 2;
  
      if (data == NULL || data_num < 2) {
          KIDS_A10_PRT("Parameters is invalid.\n");
          return;
      }
  
      for (i = 1; i < frame_num; ++i)
          data[i] = data[i << 1];
  
      memset(&data[frame_num], 0x00, frame_num * SAI_DATA_BYTES);
  }
  
  /* mono to stereo */
  static void ready_to_send(SAI_datatype *data, uint32_t data_num)
  {
      uint32_t i;
  
      if (data == NULL || data_num < 1) {
          KIDS_A10_PRT("Parameters is invalid.\n");
          return;
      }
  
      for (i = data_num - 1; i > 0; --i) {
          data[i << 1] = data[i];
          data[(i << 1) + 1] = data[i << 1];
      }
  
      data[1] = data[0];
  }
  
  /**
  * @brief This function handles DMA2 channel1 global interrupt.
  */
  void DMA2_Channel3_IRQHandler(void)
  {
      krhino_intrpt_enter();
      HAL_DMA_IRQHandler(&HANDLE_DMA);
      krhino_intrpt_exit();
  }
  
  /**
  * @brief This function handles SAI1 global interrupt.
  */
  void SAI2_IRQHandler(void)
  {
      krhino_intrpt_enter();
      HAL_SAI_IRQHandler(&HANDLE_SAI);
      krhino_intrpt_exit();
  }
  
  void HAL_SAI_TxCpltCallback(SAI_HandleTypeDef *hsai)
  {
      UpdatePointer = DATA_BUFF_LEN / 2;
      aos_sem_signal(&audio_sem);
  }
  
  void HAL_SAI_TxHalfCpltCallback(SAI_HandleTypeDef *hsai)
  {
      UpdatePointer = 0;
      aos_sem_signal(&audio_sem);
  }
  
  void HAL_SAI_RxCpltCallback(SAI_HandleTypeDef *hsai)
  {
      UpdatePointer = DATA_BUFF_LEN / 2;
      aos_sem_signal(&audio_sem);
  }
  
  void HAL_SAI_RxHalfCpltCallback(SAI_HandleTypeDef *hsai)
  {
      UpdatePointer = 0;
      aos_sem_signal(&audio_sem);
  }
  
  int record_to_flash(void)
  {
      int ret = 0;
      int uret = 0;
      int pos_buff = 0;
      uint32_t pos_flash = 0;
      uint32_t part_len = DATA_BUFF_LEN / 2;
      uint32_t part_bytes = part_len * SAI_DATA_BYTES;
      uint32_t total_size = get_audio_part_len();
  
      if (!aos_mutex_is_valid(&sai_mutex)) {
          KIDS_A10_PRT("aos_mutex_is_valid return false.\n");
          return -1;
      }
      ret = aos_mutex_lock(&sai_mutex, SAI_WAIT_TIMEOUT);
      if (ret != 0) {
          KIDS_A10_PRT("SAI is very busy now.\n");
          return -1;
      }
  
      if (!aos_sem_is_valid(&audio_sem)) {
          KIDS_A10_PRT("aos_sem_is_valid return false.\n");
          ret = -1;
          goto REC_EXIT;
      }
      ret = reinit_sai_and_dma(SAI_dir_rx_p2m);
      if (ret != 0) {
          ret = -1;
          goto REC_EXIT;
      }
  
      printf("Record time is %f seconds!\n", get_run_time());
  
      ret = HAL_SAI_Receive_DMA(&HANDLE_SAI, (uint8_t *)data_buff, DATA_BUFF_LEN);
      if (ret != 0) {
          KIDS_A10_PRT("HAL_SAI_Receive_DMA return failed.\n");
          ret = -1;
          goto REC_EXIT;
      }
  
  #ifdef FLASH_MONO_DATA
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          /* Upate the first or the second part of the buffer */
          ready_to_save(&data_buff[pos_buff], part_len);
          ret = hal_flash_write(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], part_bytes / 2);
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          /* check the end of the file */
          if ((pos_flash + part_bytes / 2) > total_size) {
              ret = 0;
              break;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error. Maybe MCU wasted too much time in saving data.\n");
              ret = -1;
              break;
          }
      }
  #else
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          /* Upate the first or the second part of the buffer */
          ret = hal_flash_write(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], part_bytes);
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          /* check the end of the file */
          if ((pos_flash + part_bytes) > total_size) {
              ret = 0;
              break;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error. Maybe MCU wasted too much time in saving data.\n");
              ret = -1;
              break;
          }
      }
  #endif
  
      uret = HAL_SAI_DMAStop(&HANDLE_SAI);
      if (uret != 0) {
          KIDS_A10_PRT("HAL_SAI_DMAStop return failed.\n");
          ret = -1;
      }
  
  REC_EXIT:
      uret = aos_mutex_unlock(&sai_mutex);
      if (uret != 0) {
          KIDS_A10_PRT("SAI release failed.\n");
          ret = -1;
      }
  
      return ret;
  }
  
  int playback_from_flash(void)
  {
      int ret = 0;
      int uret = 0;
      int pos_buff = 0;
      uint32_t pos_flash = 0;
      uint32_t part_len = DATA_BUFF_LEN / 2;
      uint32_t part_bytes = part_len * SAI_DATA_BYTES;
      uint32_t total_size = get_audio_part_len();
  
      if (!aos_mutex_is_valid(&sai_mutex)) {
          KIDS_A10_PRT("aos_mutex_is_valid return false.\n");
          return -1;
      }
      ret = aos_mutex_lock(&sai_mutex, SAI_WAIT_TIMEOUT);
      if (ret != 0) {
          KIDS_A10_PRT("SAI is very busy now.\n");
          return -1;
      }
  
      if (!aos_sem_is_valid(&audio_sem)) {
          KIDS_A10_PRT("aos_sem_is_valid return false.\n");
          ret = -1;
          goto PB_EXIT;
      }
      ret = reinit_sai_and_dma(SAI_dir_tx_m2p);
      if (ret != 0) {
          ret = -1;
          goto PB_EXIT;
      }
  
      printf("Playback time is %f seconds!\n", get_run_time());
  
  #ifdef FLASH_MONO_DATA
      ret = hal_flash_read(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], part_bytes);
      if (ret != 0) {
          ret = -1;
          goto PB_EXIT;
      }
  
      ready_to_send(data_buff, part_len);
  
      ret = HAL_SAI_Transmit_DMA(&HANDLE_SAI, (uint8_t *)data_buff, DATA_BUFF_LEN);
      if (ret != 0) {
          KIDS_A10_PRT("HAL_SAI_Transmit_DMA return failed.\n");
          ret = -1;
          goto PB_EXIT;
      }
  
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          /* Upate the first or the second part of the buffer */
          ret = hal_flash_read(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], part_bytes / 2);
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          ready_to_send(&data_buff[pos_buff], part_len / 2);
  
          /* check the end of the file */
          if ((pos_flash + part_bytes / 2) > total_size) {
              ret = 0;
              break;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error.\n");
              ret = -1;
              break;
          }
      }
  #else
      ret = hal_flash_read(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], DATA_BUFF_LEN * SAI_DATA_BYTES);
      if (ret != 0) {
          ret = -1;
          goto PB_EXIT;
      }
  
      ret = HAL_SAI_Transmit_DMA(&HANDLE_SAI, (uint8_t *)data_buff, DATA_BUFF_LEN);
      if (ret != 0) {
          KIDS_A10_PRT("HAL_SAI_Transmit_DMA return failed.\n");
          ret = -1;
          goto PB_EXIT;
      }
  
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          /* Upate the first or the second part of the buffer */
          ret = hal_flash_read(PART_FOR_AUDIO, &pos_flash, &data_buff[pos_buff], part_bytes);
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          /* check the end of the file */
          if ((pos_flash + part_bytes) > total_size) {
              ret = 0;
              break;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error.\n");
              ret = -1;
              break;
          }
      }
  #endif
  
      uret = HAL_SAI_DMAStop(&HANDLE_SAI);
      if (uret != 0) {
          KIDS_A10_PRT("HAL_SAI_DMAStop return failed.\n");
          ret = -1;
      }
  
  PB_EXIT:
      uret = aos_mutex_unlock(&sai_mutex);
      if (uret != 0) {
          KIDS_A10_PRT("SAI release failed.\n");
          ret = -1;
      }
  
      return ret;
  }
  
  static int sdaudio_open(const char *file_in_sd, int wflag)
  {
      int ret = 0;
      aos_dir_t *dp = NULL;
      int fd = 0;
      char audio_file[MAX_SIZE_PATH] = {0};
  
      dp = aos_opendir(SDCARD_AUDIO_DIR);
      if (dp == NULL) {
          ret = aos_mkdir(SDCARD_AUDIO_DIR);
          if (ret != 0) {
              KIDS_A10_PRT("aos_mkdir return failed. ret = %d\n", ret);
              return -1;
          }
      } else {
          ret = aos_closedir(dp);
          if (ret != 0) {
              KIDS_A10_PRT("aos_closedir return failed.\n");
              return -1;
          }
      }
  
      snprintf(audio_file, MAX_SIZE_PATH, SDCARD_AUDIO_DIR"/%s", file_in_sd);
      if (wflag) {
          fd = aos_open((const char*)audio_file, O_WRONLY | O_CREAT | O_TRUNC);
      } else {
          fd = aos_open((const char*)audio_file, O_RDONLY);
      }
      if (fd < 0) {
          KIDS_A10_PRT("aos_open return failed.\n");
          return -1;
      }
  
      return fd;
  }
  
  int record_to_sdcard(const char *file_in_sd, int *stop_flag)
  {
      int ret = 0;
      int uret = 0;
      int next_stop = 0;
      int fd = -1;
      ssize_t ret_size = 0;
      int pos_buff = 0;
      uint32_t part_len = DATA_BUFF_LEN / 2;
      uint32_t part_bytes = part_len * SAI_DATA_BYTES;
  
      if (file_in_sd == NULL || stop_flag == NULL || *stop_flag != 0) {
          KIDS_A10_PRT("parameters is invalid.\n");
          return -1;
      }
      if (!aos_mutex_is_valid(&sai_mutex)) {
          KIDS_A10_PRT("aos_mutex_is_valid return false.\n");
          return -1;
      }
      ret = aos_mutex_lock(&sai_mutex, SAI_WAIT_TIMEOUT);
      if (ret != 0) {
          KIDS_A10_PRT("SAI is very busy now.\n");
          return -1;
      }
      if (!aos_sem_is_valid(&audio_sem)) {
          KIDS_A10_PRT("aos_sem_is_valid return false.\n");
          ret = -1;
          goto REC_EXIT;
      }
      fd = sdaudio_open(file_in_sd, 1);
      if (fd < 0) {
          ret = -1;
          goto REC_EXIT;
      }
      aos_lseek(fd, 0, SEEK_SET);
      ret = reinit_sai_and_dma(SAI_dir_rx_p2m);
      if (ret != 0) {
          ret = -1;
          goto REC_EXIT;
      }
  
      ret = HAL_SAI_Receive_DMA(&HANDLE_SAI, (uint8_t *)data_buff, DATA_BUFF_LEN);
      if (ret != 0) {
          KIDS_A10_PRT("HAL_SAI_Receive_DMA return failed.\n");
          ret = -1;
          goto REC_EXIT;
      }
  
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          /* Upate the first or the second part of the buffer */
          ret_size = aos_write(fd, &data_buff[pos_buff], part_bytes);
          if (ret_size != part_bytes) {
              KIDS_A10_PRT("aos_write return failed.\n");
              ret = -1;
              break;
          }
  
          if (next_stop == 1) {
              ret = 0;
              break;
          }
  
          if (*stop_flag != 0) {
              next_stop = 1;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error. Maybe MCU wasted too much time in saving data.\n");
              ret = -1;
              break;
          }
      }
  
      uret = HAL_SAI_DMAStop(&HANDLE_SAI);
      if (uret != 0) {
          KIDS_A10_PRT("HAL_SAI_DMAStop return failed.\n");
          ret = -1;
      }
  
  REC_EXIT:
      if (fd >= 0) {
          uret = aos_close(fd);
          if (uret != 0) {
              KIDS_A10_PRT("aos_close return failed.\n");
              ret = -1;
          }
      }
      uret = aos_mutex_unlock(&sai_mutex);
      if (uret != 0) {
          KIDS_A10_PRT("SAI release failed.\n");
          ret = -1;
      }
  
      return ret;
  }
  
  int playback_from_sdcard(const char *file_in_sd)
  {
      int ret = 0;
      int uret = 0;
      int fd = -1;
      int next_stop = 0;
      ssize_t ret_size = 0;
      ssize_t read_len = 0;
      int pos_buff = 0;
      uint32_t part_len = DATA_BUFF_LEN / 2;
      uint32_t part_bytes = part_len * SAI_DATA_BYTES;
      off_t file_offset = 0;
      ssize_t total_size = 0;
  
      if (file_in_sd == NULL) {
          KIDS_A10_PRT("parameters is invalid.\n");
          return -1;
      }
      if (!aos_mutex_is_valid(&sai_mutex)) {
          KIDS_A10_PRT("aos_mutex_is_valid return false.\n");
          return -1;
      }
      ret = aos_mutex_lock(&sai_mutex, SAI_WAIT_TIMEOUT);
      if (ret != 0) {
          KIDS_A10_PRT("SAI is very busy now.\n");
          return -1;
      }
      if (!aos_sem_is_valid(&audio_sem)) {
          KIDS_A10_PRT("aos_sem_is_valid return false.\n");
          ret = -1;
          goto PB_EXIT;
      }
      fd = sdaudio_open(file_in_sd, 0);
      if (fd < 0) {
          ret = -1;
          goto PB_EXIT;
      }
      file_offset = aos_lseek(fd, 0, SEEK_END);
      if (file_offset <= 0) {
          KIDS_A10_PRT("aos_lseek return failed.\n");
          ret = -1;
          goto PB_EXIT;
      }
      total_size = (ssize_t)file_offset;
      aos_lseek(fd, 0, SEEK_SET);
      ret = reinit_sai_and_dma(SAI_dir_tx_m2p);
      if (ret != 0) {
          ret = -1;
          goto PB_EXIT;
      }
  
      read_len = DATA_BUFF_LEN * SAI_DATA_BYTES;
      if (total_size < read_len) {
          KIDS_A10_PRT("total_size %ld is too small.\n", total_size);
          ret = -1;
          goto PB_EXIT;
      }
      ret_size = aos_read(fd, &data_buff[pos_buff], read_len);
      if (ret_size != read_len) {
          KIDS_A10_PRT("aos_read return failed.\n");
          ret = -1;
          goto PB_EXIT;
      }
      total_size -= read_len;
  
      ret = HAL_SAI_Transmit_DMA(&HANDLE_SAI, (uint8_t *)data_buff, DATA_BUFF_LEN);
      if (ret != 0) {
          KIDS_A10_PRT("HAL_SAI_Transmit_DMA return failed.\n");
          ret = -1;
          goto PB_EXIT;
      }
  
      while (1) {
          /* Wait a callback event */
          while (UpdatePointer == -1) {
              ret = aos_sem_wait(&audio_sem, DMA_WAIT_TIMEOUT);
              if (ret != 0) {
                  KIDS_A10_PRT("DMA timeout.\n");
                  break;
              }
          }
          if (ret != 0) {
              ret = -1;
              break;
          }
          if (next_stop) {
              ret = 0;
              break;
          }
  
          pos_buff = UpdatePointer;
          UpdatePointer = -1;
  
          if (total_size < part_bytes) {
              read_len = total_size;
              memset(&data_buff[pos_buff] + read_len, 0x00, part_bytes - read_len);
          } else {
              read_len = part_bytes;
          }
  
          /* Upate the first or the second part of the buffer */
          ret_size = aos_read(fd, &data_buff[pos_buff], read_len);
          if (ret_size != read_len) {
              KIDS_A10_PRT("aos_read return failed.\n");
              ret = -1;
              break;
          }
          total_size -= read_len;
  
          if (total_size == 0) {
              next_stop = 1;
          }
  
          if (UpdatePointer != -1) {
              /* Buffer update time is too long compare to the data transfer time */
              KIDS_A10_PRT("UpdatePointer error.\n");
              ret = -1;
              break;
          }
      }
  
      uret = HAL_SAI_DMAStop(&HANDLE_SAI);
      if (uret != 0) {
          KIDS_A10_PRT("HAL_SAI_DMAStop return failed.\n");
          ret = -1;
      }
  
  PB_EXIT:
      if (fd >= 0) {
          uret = aos_close(fd);
          if (uret != 0) {
              KIDS_A10_PRT("aos_close return failed.\n");
              ret = -1;
          }
      }
      uret = aos_mutex_unlock(&sai_mutex);
      if (uret != 0) {
          KIDS_A10_PRT("SAI release failed.\n");
          ret = -1;
      }
  
      return ret;
  }
  
  int audio_init(void)
  {
      int ret = 0;
  
      if (aos_mutex_is_valid(&sai_mutex) || aos_sem_is_valid(&audio_sem)) {
          KIDS_A10_PRT("Audio module initialization had completed before now.\n");
          return -1;
      }
  
      ret = aos_mutex_new(&sai_mutex);
      if (ret != 0) {
          KIDS_A10_PRT("aos_mutex_new return failed.\n");
          return -1;
      }
      ret = aos_sem_new(&audio_sem, 0);
      if (ret != 0) {
          KIDS_A10_PRT("aos_sem_new return failed.\n");
          return -1;
      }
  
      return 0;
  }
  