/***************************************************************************
 *
 * Copyright 2015-2019 BES.
 * All rights reserved. All unpublished rights reserved.
 *
 * No part of this work may be used or reproduced in any form or by any
 * means, or stored in a database or retrieval system, without prior written
 * permission of BES.
 *
 * Use of this work is governed by a license granted by BES.
 * This work contains confidential and proprietary information of
 * BES. which is protected by copyright, trade secret,
 * trademark and other intellectual property rights.
 *
 ****************************************************************************/
#include "app_bt_trace.h"
#include "cmsis.h"
#include "cmsis_os.h"
#include "tgt_hardware.h"
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>

#ifdef WL_DET
#include "app_mic_alg.h"
#endif

#ifdef MEDIA_PLAYER_SUPPORT

#include "analog.h"
#include "app_audio.h"
#include "app_bt_stream.h"
#include "app_overlay.h"
#include "app_utils.h"
#include "audioflinger.h"
#include "hal_cmu.h"
#include "hal_timer.h"
#include "hal_uart.h"
#include "lockcqueue.h"

#include "app_bt.h"
#include "app_media_player.h"
#include "audio_prompt_sbc.h"
#include "besbt.h"
#include "res_audio_data.h"
#include "res_audio_data_cn.h"
#include "res_audio_ring.h"
#include "resources.h"

#include "app_bt_media_manager.h"
#include "btapp.h"
#include "cqueue.h"
#ifdef VOICE_DATAPATH
#include "app_ai_if.h"
#include "app_voicepath.h"
#endif

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
#include "anc_process.h"
#include "hal_codec.h"
#endif

#ifdef __THIRDPARTY
#include "app_thirdparty.h"
#endif
#if defined(IBRT)
#include "app_ibrt_if.h"
#include "app_ibrt_voice_report.h"
#include "app_tws_ibrt.h"
#endif
#ifdef __INTERACTION__
uint8_t g_findme_fadein_vol = TGT_VOLUME_LEVEL_0;
#endif
static char need_init_decoder = 1;
static btif_sbc_decoder_t *media_sbc_decoder = NULL;

#define SBC_TEMP_BUFFER_SIZE 64
#define SBC_QUEUE_SIZE (SBC_TEMP_BUFFER_SIZE * 16)
CQueue media_sbc_queue;

static float *media_sbc_eq_band_gain = NULL;

#ifdef __BT_ANC__
#define APP_AUDIO_PLAYBACK_BUFF_SIZE (1024 * 3)
#else
#define APP_AUDIO_PLAYBACK_BUFF_SIZE (1024 * 4)
#endif

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
static enum AUD_BITS_T sample_size_play_bt;
static enum AUD_SAMPRATE_T sample_rate_play_bt;
static uint32_t data_size_play_bt;

static uint8_t *playback_buf_bt;
static uint32_t playback_size_bt;
static int32_t playback_samplerate_ratio_bt;

static uint8_t *playback_buf_mc;
static uint32_t playback_size_mc;
static enum AUD_CHANNEL_NUM_T playback_ch_num_bt;
#endif

#define SBC_FRAME_LEN 64 // 0x5c   /* pcm 512 bytes*/
static U8 *g_app_audio_data = NULL;
static uint32_t g_app_audio_length = 0;
static uint32_t g_app_audio_read = 0;

static uint32_t g_play_continue_mark = 0;

static uint8_t app_play_sbc_stop_proc_cnt = 0;

static uint16_t g_prompt_chnlsel = PROMOT_ID_BIT_MASK_CHNLSEl_ALL;

// for continue play

#define MAX_SOUND_NUMBER 10

typedef struct tMediaSoundMap {
  U8 *data;       // total files
  uint32_t fsize; // file index

} _tMediaSoundMap;

const tMediaSoundMap *media_sound_map;

const tMediaSoundMap media_sound_map_cn[MAX_SOUND_NUMBER] = {
    {(U8 *)CN_SOUND_ZERO, CN_SOUND_ZERO_len},
    {(U8 *)CN_SOUND_ONE, CN_SOUND_ONE_len},
    {(U8 *)CN_SOUND_TWO, CN_SOUND_TWO_len},
    {(U8 *)CN_SOUND_THREE, CN_SOUND_THREE_len},
    {(U8 *)CN_SOUND_FOUR, CN_SOUND_FOUR_len},
    {(U8 *)CN_SOUND_FIVE, CN_SOUND_FIVE_len},
    {(U8 *)CN_SOUND_SIX, CN_SOUND_SIX_len},
    {(U8 *)CN_SOUND_SEVEN, CN_SOUND_SEVEN_len},
    {(U8 *)CN_SOUND_EIGHT, CN_SOUND_EIGHT_len},
    {(U8 *)CN_SOUND_NINE, CN_SOUND_NINE_len},
};

const tMediaSoundMap media_sound_map_en[MAX_SOUND_NUMBER] = {
    {(U8 *)EN_SOUND_ZERO, EN_SOUND_ZERO_len},
    {(U8 *)EN_SOUND_ONE, EN_SOUND_ONE_len},
    {(U8 *)EN_SOUND_TWO, EN_SOUND_TWO_len},
    {(U8 *)EN_SOUND_THREE, EN_SOUND_THREE_len},
    {(U8 *)EN_SOUND_FOUR, EN_SOUND_FOUR_len},
    {(U8 *)EN_SOUND_FIVE, EN_SOUND_FIVE_len},
    {(U8 *)EN_SOUND_SIX, EN_SOUND_SIX_len},
    {(U8 *)EN_SOUND_SEVEN, EN_SOUND_SEVEN_len},
    {(U8 *)EN_SOUND_EIGHT, EN_SOUND_EIGHT_len},
    {(U8 *)EN_SOUND_NINE, EN_SOUND_NINE_len},
};

const uint8_t BT_MUTE[] = {
#include "res/SOUND_MUTE.txt"
};

char Media_player_number[MAX_PHB_NUMBER];

typedef struct tPlayContContext {
  uint32_t g_play_continue_total; // total files
  uint32_t g_play_continue_n;     // file index

  uint32_t g_play_continue_fread; // per file have readed

  U8 g_play_continue_array[MAX_PHB_NUMBER];

} _tPlayContContext;

tPlayContContext pCont_context;

APP_AUDIO_STATUS MSG_PLAYBACK_STATUS;
APP_AUDIO_STATUS *ptr_msg_playback = &MSG_PLAYBACK_STATUS;

static int g_language = MEDIA_DEFAULT_LANGUAGE;
#ifdef AUDIO_LINEIN
static enum AUD_SAMPRATE_T app_play_audio_sample_rate = AUD_SAMPRATE_16000;
#endif

#define PREFIX_AUDIO(name)                                                     \
  ((g_language == MEDIA_DEFAULT_LANGUAGE) ? EN_##name : CN_##name)

#define PROMPT_MIX_PROPERTY_PTR_FROM_ENTRY_INDEX(index)                        \
  ((PROMPT_MIX_PROPERTY_T *)((uintptr_t)__mixprompt_property_table_start +     \
                             (index) * sizeof(PROMPT_MIX_PROPERTY_T)))

int media_audio_init(void) {
  const float EQLevel[25] = {
      0.0630957, 0.0794328, 0.1,       0.1258925, 0.1584893,
      0.1995262, 0.2511886, 0.3162278, 0.398107,  0.5011872,
      0.6309573, 0.794328,  1,         1.258925,  1.584893,
      1.995262,  2.5118864, 3.1622776, 3.9810717, 5.011872,
      6.309573,  7.943282,  10,        12.589254, 15.848932}; //-12~12
  uint8_t *buff = NULL;
  uint8_t i;

  app_audio_mempool_get_buff((uint8_t **)&media_sbc_eq_band_gain,
                             CFG_HW_AUD_EQ_NUM_BANDS * sizeof(float));

  for (i = 0; i < CFG_HW_AUD_EQ_NUM_BANDS; i++) {
    media_sbc_eq_band_gain[i] = EQLevel[12];
  }

  app_audio_mempool_get_buff(&buff, SBC_QUEUE_SIZE);
  memset(buff, 0, SBC_QUEUE_SIZE);

  LOCK_APP_AUDIO_QUEUE();
  APP_AUDIO_InitCQueue(&media_sbc_queue, SBC_QUEUE_SIZE, buff);
  UNLOCK_APP_AUDIO_QUEUE();

  app_audio_mempool_get_buff((uint8_t **)&media_sbc_decoder,
                             sizeof(btif_sbc_decoder_t) + 4);

  need_init_decoder = 1;

  app_play_sbc_stop_proc_cnt = 0;

  return 0;
}
static int decode_sbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len) {
  uint8_t underflow = 0;

  int r = 0;
  unsigned char *e1 = NULL, *e2 = NULL;
  unsigned int len1 = 0, len2 = 0;

  static btif_sbc_pcm_data_t pcm_data;
  bt_status_t ret = BT_STS_SUCCESS;
  unsigned short byte_decode = 0;

  pcm_data.data = (unsigned char *)pcm_buffer;

  LOCK_APP_AUDIO_QUEUE();
again:
  if (need_init_decoder) {
    pcm_data.data = (unsigned char *)pcm_buffer;
    pcm_data.dataLen = 0;
    btif_sbc_init_decoder(media_sbc_decoder);
  }

get_again:
  len1 = len2 = 0;
  r = APP_AUDIO_PeekCQueue(&media_sbc_queue, SBC_TEMP_BUFFER_SIZE, &e1, &len1,
                           &e2, &len2);

  if (r == CQ_ERR) {
    need_init_decoder = 1;
    underflow = 1;
    r = pcm_data.dataLen;
    TRACE_MEDIA_PLAYESTREAM_I("[DECODE_SBC][END]");
    goto exit;
  }
  if (!len1) {
    TRACE_MEDIA_PLAYESTREAM_I("[DECODE_SBC][LOOP] len1 underflow %d/%d\n", len1,
                              len2);
    goto get_again;
  }

  ret = btif_sbc_decode_frames(media_sbc_decoder, (unsigned char *)e1, len1,
                               &byte_decode, &pcm_data, pcm_len,
                               media_sbc_eq_band_gain);

  if (ret == BT_STS_CONTINUE) {
    need_init_decoder = 0;
    APP_AUDIO_DeCQueue(&media_sbc_queue, 0, len1);
    goto again;

    /* back again */
  } else if (ret == BT_STS_SUCCESS) {
    need_init_decoder = 0;
    r = pcm_data.dataLen;
    pcm_data.dataLen = 0;

    APP_AUDIO_DeCQueue(&media_sbc_queue, 0, byte_decode);

    // TRACE_MEDIA_PLAYESTREAM_I("p %d\n", pcm_data.sampleFreq);

    /* leave */
  } else if (ret == BT_STS_FAILED) {
    need_init_decoder = 1;
    r = pcm_data.dataLen;
    TRACE_MEDIA_PLAYESTREAM_E("[DECODE_SBC] err\n");

    APP_AUDIO_DeCQueue(&media_sbc_queue, 0, byte_decode);

    /* leave */
  } else if (ret == BT_STS_NO_RESOURCES) {
    need_init_decoder = 0;

    TRACE_MEDIA_PLAYESTREAM_I("[DECODE_SBC] no\n");

    /* leav */
    r = 0;
  }

exit:
  if (underflow) {
    TRACE_MEDIA_PLAYESTREAM_I("[DECODE_SBC][END] len:%d\n ", pcm_len);
  }
  UNLOCK_APP_AUDIO_QUEUE();
  return r;
}

static int store_sbc_buffer(unsigned char *buf, unsigned int len) {
  int nRet;

  LOCK_APP_AUDIO_QUEUE();
  nRet = APP_AUDIO_EnCQueue(&media_sbc_queue, buf, len);
  UNLOCK_APP_AUDIO_QUEUE();

  return nRet;
}

#if defined(IBRT)

#define PENDING_SYNC_PROMPT_BUFFER_CNT 8
// cleared when tws is disconnected
static uint16_t pendingSyncPromptId[PENDING_SYNC_PROMPT_BUFFER_CNT];
static uint8_t pending_sync_prompt_in_index = 0;
static uint8_t pending_sync_prompt_out_index = 0;
static uint8_t pending_sync_prompt_cnt = 0;

void app_tws_sync_prompt_manager_reset(void) {
  pending_sync_prompt_in_index = 0;
  pending_sync_prompt_out_index = 0;
  pending_sync_prompt_cnt = 0;
}

void app_tws_sync_prompt_check(void) {
  if (0 == pending_sync_prompt_cnt) {
    app_bt_active_mode_clear(ACTIVE_MODE_KEEPER_SYNC_VOICE_PROMPT,
                             UPDATE_ACTIVE_MODE_FOR_ALL_LINKS);
  }

  if (IBRT_ACTIVE_MODE != app_ibrt_if_get_bt_ctrl_ctx()->tws_mode) {
    return;
  }

  bool isPlayPendingPrompt = false;
  uint16_t promptIdToPlay = 0;

  uint32_t lock = int_lock_global();
  if (pending_sync_prompt_cnt > 0) {
    isPlayPendingPrompt = true;
    promptIdToPlay = pendingSyncPromptId[pending_sync_prompt_out_index];
    pending_sync_prompt_out_index++;
    if (PENDING_SYNC_PROMPT_BUFFER_CNT == pending_sync_prompt_out_index) {
      pending_sync_prompt_out_index = 0;
    }
    pending_sync_prompt_cnt--;
  }
  int_unlock_global(lock);

  if (isPlayPendingPrompt) {
    TRACE_MEDIA_PLAYESTREAM_I("[POP_PENDING_PROMPT] 0x%x to play",
                              promptIdToPlay);
    app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_MEDIA,
                                  0, promptIdToPlay);
  }
}
#endif

void trigger_media_play(AUD_ID_ENUM id, uint8_t device_id, uint16_t aud_pram) {
  uint16_t convertedId = (uint8_t)id;
  convertedId |= aud_pram;
  app_audio_manager_sendrequest(APP_BT_STREAM_MANAGER_START, BT_STREAM_MEDIA,
                                device_id, convertedId);
}
void trigger_media_stop(AUD_ID_ENUM id, uint8_t device_id) {
  /* Only the stop loop mode is supported */
  if (id == AUDIO_ID_FIND_MY_BUDS)
    app_play_sbc_stop_proc_cnt = 1;
}

uint32_t media_playAudioSideSelect(AUD_ID_ENUM id, uint8_t device_id,
                                   uint16_t side_select) {
  trigger_media_play(id, device_id, PROMOT_ID_BIT_MASK_MERGING | side_select);
  return 0;
}

uint32_t media_PlayAudio(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id,
                     PROMOT_ID_BIT_MASK_MERGING |
                         PROMOT_ID_BIT_MASK_CHNLSEl_ALL);
  return 0;
}

void media_PlayAudio_standalone(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id, false);
}

void media_PlayAudio_locally(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id,
                     PROMOT_ID_BIT_MASK_MERGING |
                         PROMOT_ID_BIT_MASK_CHNLSEl_ALL);
}

void media_PlayAudio_standalone_locally(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id, PROMOT_ID_BIT_MASK_CHNLSEl_ALL);
}

void media_PlayAudio_remotely(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id,
                     PROMOT_ID_BIT_MASK_MERGING |
                         PROMOT_ID_BIT_MASK_CHNLSEl_ALL);
}

void media_PlayAudio_standalone_remotely(AUD_ID_ENUM id, uint8_t device_id) {
  trigger_media_play(id, device_id, PROMOT_ID_BIT_MASK_CHNLSEl_ALL);
}

AUD_ID_ENUM media_GetCurrentPrompt(uint8_t device_id) {
  AUD_ID_ENUM currentPromptId = AUD_ID_INVALID;
  if (app_bt_stream_isrun(APP_PLAY_BACK_AUDIO)) {
    currentPromptId = app_get_current_standalone_promptId();
  }
#ifdef MIX_AUDIO_PROMPT_WITH_A2DP_MEDIA_ENABLED
  else if (audio_prompt_is_playing_ongoing()) {
    currentPromptId = (AUD_ID_ENUM)audio_prompt_get_prompt_id();
  }
#endif
  return currentPromptId;
}

#define IsDigit(c) (((c) >= '0') && ((c) <= '9'))
void media_Set_IncomingNumber(const char *pNumber) {
  char *p_num = Media_player_number;
  uint8_t cnt = 0;
  for (uint8_t idx = 0; idx < MAX_PHB_NUMBER; idx++) {
    if (*(pNumber + idx) == 0)
      break;

    if (IsDigit(*(pNumber + idx))) {
      *(p_num + cnt) = *(pNumber + idx);
      TRACE_MEDIA_PLAYESTREAM_I("[INCOMINGNUMBER] cnt %d ,p_num  %d", cnt,
                                *(p_num + cnt));
      cnt++;
    }
  }
}

PROMPT_MIX_PROPERTY_T *get_prompt_mix_property(uint16_t promptId) {
  for (uint32_t index = 0;
       index < ((uint32_t)(uintptr_t)__mixprompt_property_table_end -
                (uint32_t)(uintptr_t)__mixprompt_property_table_start) /
                   sizeof(PROMPT_MIX_PROPERTY_T);
       index++) {
    if (PROMPT_MIX_PROPERTY_PTR_FROM_ENTRY_INDEX(index)->promptId == promptId) {
      return PROMPT_MIX_PROPERTY_PTR_FROM_ENTRY_INDEX(index);
    }
  }

  return NULL;
}
/*
Reference information for how to pass
parameters into PROMPT_MIX_PROPERTY_TO_ADD:

PROMPT_MIX_PROPERTY_TO_ADD(
promptId,
volume_level_override,
coeff_for_mix_prompt_for_music,
coeff_for_mix_music_for_music,
coeff_for_mix_prompt_for_call,
coeff_for_mix_call_for_call)
*/
void media_runtime_audio_prompt_update(uint16_t id, uint8_t **ptr,
                                       uint32_t *len) {
  switch (id) {
  case AUD_ID_POWER_ON:
    g_app_audio_data =
        (g_language == MEDIA_DEFAULT_LANGUAGE)
            ? (U8 *)EN_SOUND_POWER_ON
            : (U8 *)CN_SOUND_POWER_ON; // aud_get_reouce((AUD_ID_ENUM)id,
                                 // &g_app_audio_length, &type);
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_POWER_ON_len
                             : CN_SOUND_POWER_ON_len;
    break;
  case AUD_ID_POWER_OFF:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_POWER_OFF
                           : (U8 *)CN_SOUND_POWER_OFF;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_POWER_OFF_len
                             : CN_SOUND_POWER_OFF_len;
    break;
  case AUD_ID_BT_PAIR_ENABLE:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_PAIR_ENABLE
                           : (U8 *)CN_SOUND_PAIR_ENABLE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_PAIR_ENABLE_len
                             : CN_SOUND_PAIR_ENABLE_len;
    break;
  case AUD_ID_BT_PAIRING:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_PAIRING
                           : (U8 *)CN_SOUND_PAIRING;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_PAIRING_len
                             : CN_SOUND_PAIRING_len;
    break;
  case AUD_ID_BT_PAIRING_SUC:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_PAIRING_SUCCESS
                           : (U8 *)CN_SOUND_PAIRING_SUCCESS;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_PAIRING_SUCCESS_len
                             : CN_SOUND_PAIRING_SUCCESS_len;
    break;
  case AUD_ID_BT_PAIRING_FAIL:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_PAIRING_FAIL
                           : (U8 *)CN_SOUND_PAIRING_FAIL;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_PAIRING_FAIL_len
                             : CN_SOUND_PAIRING_FAIL_len;
    break;
  case AUD_ID_BT_CALL_REFUSE:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_REFUSE
                           : (U8 *)CN_SOUND_REFUSE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_REFUSE_len
                             : CN_SOUND_REFUSE_len;
    break;
  case AUD_ID_BT_CALL_OVER:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_OVER
                           : (U8 *)CN_SOUND_OVER;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_OVER_len
                             : CN_SOUND_OVER_len;
    break;
  case AUD_ID_BT_CALL_ANSWER:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_ANSWER
                           : (U8 *)CN_SOUND_ANSWER;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_ANSWER_len
                             : CN_SOUND_ANSWER_len;
    break;
  case AUD_ID_BT_CALL_HUNG_UP:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_HUNG_UP
                           : (U8 *)CN_SOUND_HUNG_UP;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_HUNG_UP_len
                             : CN_SOUND_HUNG_UP_len;
    break;
  case AUD_ID_BT_CALL_INCOMING_CALL:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_INCOMING_CALL
                           : (U8 *)CN_SOUND_INCOMING_CALL;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_INCOMING_CALL_len
                             : CN_SOUND_INCOMING_CALL_len;
    break;
  case AUD_ID_BT_CHARGE_PLEASE:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_CHARGE_PLEASE
                           : (U8 *)CN_SOUND_CHARGE_PLEASE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_CHARGE_PLEASE_len
                             : CN_SOUND_CHARGE_PLEASE_len;
    break;
  case AUD_ID_BT_CHARGE_FINISH:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_CHARGE_FINISH
                           : (U8 *)CN_SOUND_CHARGE_FINISH;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_CHARGE_FINISH_len
                             : CN_SOUND_CHARGE_FINISH_len;
    break;
  case AUD_ID_BT_CONNECTED:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_CONNECTED
                           : (U8 *)CN_SOUND_CONNECTED;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_CONNECTED_len
                             : CN_SOUND_CONNECTED_len;
    break;
  case AUD_ID_BT_DIS_CONNECT:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_DIS_CONNECT
                           : (U8 *)CN_SOUND_DIS_CONNECT;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_DIS_CONNECT_len
                             : CN_SOUND_DIS_CONNECT_len;
    break;
  case AUD_ID_BT_WARNING:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_WARNING
                           : (U8 *)CN_SOUND_WARNING;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_WARNING_len
                             : CN_SOUND_WARNING_len;
    break;
  case AUDIO_ID_BT_ALEXA_START:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_ALEXA_START
                           : (U8 *)CN_SOUND_ALEXA_START;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_ALEXA_START_len
                             : CN_SOUND_ALEXA_START_len;
    break;
  case AUDIO_ID_BT_ALEXA_STOP:
  case AUDIO_ID_FIND_MY_BUDS:
  case AUDIO_ID_FIND_TILE:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_ALEXA_STOP
                           : (U8 *)CN_SOUND_ALEXA_STOP;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_ALEXA_STOP_len
                             : CN_SOUND_ALEXA_STOP_len;
    break;
  case AUDIO_ID_BT_GSOUND_MIC_OPEN:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_GSOUND_MIC_OPEN
                           : (U8 *)CN_SOUND_GSOUND_MIC_OPEN;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_GSOUND_MIC_OPEN_len
                             : CN_SOUND_GSOUND_MIC_OPEN_len;
    break;
  case AUDIO_ID_BT_GSOUND_MIC_CLOSE:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_GSOUND_MIC_CLOSE
                           : (U8 *)CN_SOUND_GSOUND_MIC_CLOSE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_GSOUND_MIC_CLOSE_len
                             : CN_SOUND_GSOUND_MIC_CLOSE_len;
    break;
  case AUDIO_ID_BT_GSOUND_NC:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_GSOUND_NC
                           : (U8 *)CN_SOUND_GSOUND_NC;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_GSOUND_NC_len
                             : CN_SOUND_GSOUND_NC_len;
    break;
  case AUD_ID_LANGUAGE_SWITCH:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_LANGUAGE_SWITCH
                           : (U8 *)CN_SOUND_LANGUAGE_SWITCH;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_LANGUAGE_SWITCH_len
                             : CN_SOUND_LANGUAGE_SWITCH_len;
    break;
  case AUDIO_ID_BT_MUTE:
    g_app_audio_data = (U8 *)BT_MUTE;
    g_app_audio_length = sizeof(BT_MUTE);
    break;
  case AUD_ID_NUM_0:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_ZERO
                           : (U8 *)CN_SOUND_ZERO;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_ZERO_len
                             : CN_SOUND_ZERO_len;
    break;
  case AUD_ID_NUM_1:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_ONE
                           : (U8 *)CN_SOUND_ONE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_ONE_len
                             : CN_SOUND_ONE_len;
    break;
  case AUD_ID_NUM_2:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_TWO
                           : (U8 *)CN_SOUND_TWO;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_TWO_len
                             : CN_SOUND_TWO_len;
    break;
  case AUD_ID_NUM_3:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_THREE
                           : (U8 *)CN_SOUND_THREE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_THREE_len
                             : CN_SOUND_THREE_len;
    break;
  case AUD_ID_NUM_4:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_FOUR
                           : (U8 *)CN_SOUND_FOUR;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_FOUR_len
                             : CN_SOUND_FOUR_len;
    break;
  case AUD_ID_NUM_5:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_FIVE
                           : (U8 *)CN_SOUND_FIVE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_FIVE_len
                             : CN_SOUND_FIVE_len;
    break;
  case AUD_ID_NUM_6:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_SIX
                           : (U8 *)CN_SOUND_SIX;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_SIX_len
                             : CN_SOUND_SIX_len;
    break;
  case AUD_ID_NUM_7:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_SEVEN
                           : (U8 *)CN_SOUND_SEVEN;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_SEVEN_len
                             : CN_SOUND_SEVEN_len;
    break;
  case AUD_ID_NUM_8:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_EIGHT
                           : (U8 *)CN_SOUND_EIGHT;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_EIGHT_len
                             : CN_SOUND_EIGHT_len;
    break;
  case AUD_ID_NUM_9:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_NINE
                           : (U8 *)CN_SOUND_NINE;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_NINE_len
                             : CN_SOUND_NINE_len;
    break;
#ifdef __BT_WARNING_TONE_MERGE_INTO_STREAM_SBC__
  case AUD_ID_RING_WARNING:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)RES_AUD_RING_SAMPRATE_16000
                           : (U8 *)RES_AUD_RING_SAMPRATE_16000;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? sizeof(RES_AUD_RING_SAMPRATE_16000)
                             : sizeof(RES_AUD_RING_SAMPRATE_16000);
    break;
#endif
#ifdef __INTERACTION__
  case AUD_ID_BT_FINDME:
    g_app_audio_data = (g_language == MEDIA_DEFAULT_LANGUAGE)
                           ? (U8 *)EN_SOUND_FINDME
                           : (U8 *)CN_SOUND_FINDME;
    g_app_audio_length = (g_language == MEDIA_DEFAULT_LANGUAGE)
                             ? EN_SOUND_FINDME_len
                             : CN_SOUND_FINDME_len;
    break;
#endif
  case AUDIO_ID_BT_DUDU:
    g_app_audio_data = (U8 *)EN_DUDU;
    g_app_audio_length = EN_DUDU_len;
    break;
  case AUDIO_ID_BT_DU:
    g_app_audio_data = (U8 *)EN_DUDU;
    g_app_audio_length = EN_DUDU_len;
    break;
  default:
    g_app_audio_length = 0;
    break;
  }

  *ptr = g_app_audio_data;
  *len = g_app_audio_length;
}

void media_Play_init_audio(uint16_t aud_id) {

  if (aud_id == AUD_ID_BT_CALL_INCOMING_NUMBER) {
    g_play_continue_mark = 1;

    if (g_language == MEDIA_DEFAULT_LANGUAGE)
      media_sound_map = media_sound_map_en;
    else
      media_sound_map = media_sound_map_cn;

    memset(&pCont_context, 0x0, sizeof(pCont_context));

    pCont_context.g_play_continue_total =
        strlen((const char *)Media_player_number);

    for (uint32_t i = 0;
         (i < pCont_context.g_play_continue_total) && (i < MAX_PHB_NUMBER);
         i++) {
      pCont_context.g_play_continue_array[i] = Media_player_number[i] - '0';

      TRACE_MEDIA_PLAYESTREAM_I("[INIT_AUDIO] array[%d] = %d, total =%d", i,
                                pCont_context.g_play_continue_array[i],
                                pCont_context.g_play_continue_total);
    }
  } else {
    g_app_audio_read = 0;
    g_play_continue_mark = 0;

    media_runtime_audio_prompt_update(aud_id, &g_app_audio_data,
                                      &g_app_audio_length);
  }
}
uint32_t app_play_sbc_more_data_fadeout(int16_t *buf, uint32_t len) {
  uint32_t i;
  uint32_t j = 0;

  for (i = len; i > 0; i--) {
    *(buf + j) = *(buf + j) * i / len;
    j++;
  }

  return len;
}

static uint32_t need_fadein_len = 0;
static uint32_t need_fadein_len_processed = 0;

int app_play_sbc_more_data_fadein_config(uint32_t len) {
  TRACE_MEDIA_PLAYESTREAM_I("[FADEIN] config l:%d", len);
  need_fadein_len = len;
  need_fadein_len_processed = 0;
  return 0;
}
uint32_t app_play_sbc_more_data_fadein(int16_t *buf, uint32_t len) {
  uint32_t i;
  uint32_t j = 0;
  uint32_t base;
  uint32_t dest;

  base = need_fadein_len_processed;
  dest = need_fadein_len_processed + len < need_fadein_len
             ? need_fadein_len_processed + len
             : need_fadein_len_processed;

  if (base >= dest) {
    //        TRACE_MEDIA_PLAYESTREAM_I("skip fadein");
    return len;
  }
  //    TRACE_MEDIA_PLAYESTREAM_I("fadein l:%d base:%d dest:%d", len, base,
  //    dest); DUMP16("%5d ", buf, 20); DUMP16("%5d ", buf+len-19, 20);

  for (i = base; i < dest; i++) {
    *(buf + j) = *(buf + j) * i / need_fadein_len;
    j++;
  }

  need_fadein_len_processed += j;
  //    DUMP16("%05d ", buf, 20);
  //    DUMP16("%5d ", buf+len-19, 20);
  return len;
}

uint32_t app_play_single_sbc_more_data(uint8_t *buf, uint32_t len) {
  // int32_t stime, etime;
  // U16 byte_decode;
  uint32_t l = 0;

  // TRACE_MEDIA_PLAYESTREAM_I("app_play_sbc_more_data : %d, %d",
  // g_app_audio_read, g_app_audio_length);

  if (g_app_audio_read < g_app_audio_length) {
    unsigned int available_len = 0;
    unsigned int store_len = 0;

    available_len = AvailableOfCQueue(&media_sbc_queue);
    store_len = (g_app_audio_length - g_app_audio_read) > available_len
                    ? available_len
                    : (g_app_audio_length - g_app_audio_read);
    store_sbc_buffer((unsigned char *)(g_app_audio_data + g_app_audio_read),
                     store_len);
    g_app_audio_read += store_len;
  }

  l = decode_sbc_frame(buf, len);

  if (l != len) {
    g_app_audio_read = g_app_audio_length;
    // af_stream_stop(AUD_STREAM_PLAYBACK);
    // af_stream_close(AUD_STREAM_PLAYBACK);
    TRACE_MEDIA_PLAYESTREAM_I(
        "[SINGLE_SBC_MORE_DATA][END] length:%d len:%d l:%d", g_app_audio_length,
        len, l);
  }

  return l;
}

/* play continue sound */
uint32_t app_play_continue_sbc_more_data(uint8_t *buf, uint32_t len) {

  uint32_t l, n, fsize = 0;

  U8 *pdata = NULL;

  // store data
  unsigned int available_len = 0;
  unsigned int store_len = 0;

  if (pCont_context.g_play_continue_n < pCont_context.g_play_continue_total) {
    do {
      n = pCont_context.g_play_continue_n;
      pdata = media_sound_map[pCont_context.g_play_continue_array[n]].data;
      fsize = media_sound_map[pCont_context.g_play_continue_array[n]].fsize;

      available_len = AvailableOfCQueue(&media_sbc_queue);
      if (!available_len)
        break;

      store_len = (fsize - pCont_context.g_play_continue_fread) > available_len
                      ? available_len
                      : (fsize - pCont_context.g_play_continue_fread);
      store_sbc_buffer(
          (unsigned char *)(pdata + pCont_context.g_play_continue_fread),
          store_len);
      pCont_context.g_play_continue_fread += store_len;
      if (pCont_context.g_play_continue_fread == fsize) {
        pCont_context.g_play_continue_n++;
        pCont_context.g_play_continue_fread = 0;
      }
    } while (pCont_context.g_play_continue_n <
             pCont_context.g_play_continue_total);
  }

  l = decode_sbc_frame(buf, len);

  if (l != len) {
    TRACE_MEDIA_PLAYESTREAM_I("[CONTINUE_SBC_MORE_DATA][END]");
  }

  return l;
}

uint32_t app_play_sbc_channel_select(int16_t *dst_buf, int16_t *src_buf,
                                     uint32_t src_len) {
#if defined(IBRT)
  if (IS_PROMPT_CHNLSEl_ALL(g_prompt_chnlsel) ||
      app_ibrt_voice_report_is_me(
          PROMPT_CHNLSEl_FROM_ID_VALUE(g_prompt_chnlsel))) {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = dst_buf[i * 2 + 1] = src_buf[i];
    }
  } else {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = dst_buf[i * 2 + 1] = 0;
    }
  }
#else
  if (IS_PROMPT_CHNLSEl_ALL(g_prompt_chnlsel)) {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = dst_buf[i * 2 + 1] = src_buf[i];
    }
  } else if (IS_PROMPT_CHNLSEl_LCHNL(g_prompt_chnlsel)) {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = src_buf[i];
      dst_buf[i * 2 + 1] = 0;
    }
  } else if (IS_PROMPT_CHNLSEl_RCHNL(g_prompt_chnlsel)) {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = 0;
      dst_buf[i * 2 + 1] = src_buf[i];
    }
  } else {
    // Copy from tail so that it works even if dst_buf == src_buf
    for (int i = (int)(src_len - 1); i >= 0; i--) {
      dst_buf[i * 2 + 0] = dst_buf[i * 2 + 1] = 0;
    }
  }
#endif
  return 0;
}

#ifdef __BT_ANC__
extern uint8_t bt_sco_samplerate_ratio;
extern void us_fir_init(void);
extern U32 us_fir_run(short *src_buf, short *dst_buf, U32 in_samp_num);
#endif

uint32_t g_cache_buff_sz = 0;

static int16_t *app_play_sbc_cache = NULL;
uint32_t app_play_sbc_more_data(uint8_t *buf, uint32_t len) {
#if defined(IBRT)
  app_ibrt_voice_report_trigger_checker();
#endif

#ifdef VOICE_DATAPATH
  if (app_voicepath_get_stream_pending_state(VOICEPATH_STREAMING)) {
    af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE);
#ifdef MIX_MIC_DURING_MUSIC
    app_voicepath_enable_hw_sidetone(0, HW_SIDE_TONE_MAX_ATTENUATION_COEF);
#endif
    app_voicepath_set_stream_state(VOICEPATH_STREAMING, true);
    app_voicepath_set_pending_started_stream(VOICEPATH_STREAMING, false);
  }
#endif
  uint32_t l = 0;

  memset(buf, 0, len);

#if defined(MEDIA_PLAY_24BIT)
  len /= 2;
#endif

#ifdef __BT_ANC__
  uint32_t dec_len = len / bt_sco_samplerate_ratio;
#endif

  if (app_play_sbc_cache)
    memset(app_play_sbc_cache, 0, g_cache_buff_sz);

  if (app_play_sbc_stop_proc_cnt) {
    if (app_play_sbc_stop_proc_cnt == 1) {
      app_play_sbc_stop_proc_cnt = 2;
    } else if (app_play_sbc_stop_proc_cnt == 2) {
      app_play_sbc_stop_proc_cnt = 3;

      // For 8K sample rate data, it takes about 4ms (or 12ms if h/w resample in
      // use) from codec to DAC PA. The playback stream should be stopped after
      // the last data arrives at DAC PA, otherwise there might be some pop
      // sound.
      app_play_audio_stop();
    }
  } else {
    if (app_play_sbc_cache) {
#ifdef __BT_ANC__
      len = dec_len;
#endif
      if (g_play_continue_mark) {
        l = app_play_continue_sbc_more_data((uint8_t *)app_play_sbc_cache,
                                            len / 2);
      } else {
        l = app_play_single_sbc_more_data((uint8_t *)app_play_sbc_cache,
                                          len / 2);
      }
      if (l != len / 2) {
#ifdef __BT_ANC__
        len = dec_len * 3;
#endif
        memset(app_play_sbc_cache + l, 0, len / 2 - l);
        app_play_sbc_stop_proc_cnt = 1;
      }
#ifdef __BT_ANC__
      len = dec_len * 3;
      l = l * 3;
      us_fir_run((short *)app_play_sbc_cache, (short *)buf, dec_len / 2 / 2);
      app_play_sbc_channel_select((int16_t *)buf, (int16_t *)buf, len / 2 / 2);
#else
      app_play_sbc_channel_select((int16_t *)buf, app_play_sbc_cache,
                                  len / 2 / 2);
#endif

#if defined(MEDIA_PLAY_24BIT)
      int32_t *buf32 = (int32_t *)buf;
      int16_t *buf16 = (int16_t *)buf;

      for (int16_t i = len / 2 - 1; i >= 0; i--) {
        buf32[i] = ((int32_t)buf16[i] << 8);
      }
      len *= 2;
#endif
    } else {
#if defined(MEDIA_PLAY_24BIT)
      len *= 2;
#endif
      memset(buf, 0, len);
    }
  }

  return l;
}

#ifdef AUDIO_LINEIN
static uint8_t app_play_lineinmode_merge = 0;
static uint8_t app_play_lineinmode_mode = 0;

inline static void app_play_audio_lineinmode_mono_merge(int16_t *aud_buf_mono,
                                                        int16_t *ring_buf_mono,
                                                        uint32_t aud_buf_len) {
  uint32_t i = 0;
  for (i = 0; i < aud_buf_len; i++) {
    aud_buf_mono[i] = (aud_buf_mono[i] >> 1) + (ring_buf_mono[i] >> 1);
  }
}

inline static void app_play_audio_lineinmode_stereo_merge(
    int16_t *aud_buf_stereo, int16_t *ring_buf_mono, uint32_t aud_buf_len) {
  uint32_t aud_buf_stereo_offset = 0;
  uint32_t ring_buf_mono_offset = 0;
  for (aud_buf_stereo_offset = 0; aud_buf_stereo_offset < aud_buf_len;) {
    aud_buf_stereo[aud_buf_stereo_offset] =
        aud_buf_stereo[aud_buf_stereo_offset] +
        (ring_buf_mono[ring_buf_mono_offset] >> 1);
    aud_buf_stereo_offset++;
    aud_buf_stereo[aud_buf_stereo_offset] =
        aud_buf_stereo[aud_buf_stereo_offset] +
        (ring_buf_mono[ring_buf_mono_offset] >> 1);
    aud_buf_stereo_offset++;
    ring_buf_mono_offset++;
  }
}

uint32_t app_play_audio_lineinmode_more_data(uint8_t *buf, uint32_t len) {
  uint32_t l = 0;
  if (app_play_lineinmode_merge && app_play_sbc_cache) {
    TRACE(1, "line in mode:%d ", len);
    if (app_play_lineinmode_mode == 1) {
      if (g_play_continue_mark) {
        l = app_play_continue_sbc_more_data((uint8_t *)app_play_sbc_cache, len);
      } else {
        l = app_play_single_sbc_more_data((uint8_t *)app_play_sbc_cache, len);
      }
      if (l != len) {
        memset(app_play_sbc_cache + l, 0, len - l);
        app_play_lineinmode_merge = 0;
      }
      app_play_audio_lineinmode_mono_merge(
          (int16_t *)buf, (int16_t *)app_play_sbc_cache, len / 2);
    } else if (app_play_lineinmode_mode == 2) {
      if (g_play_continue_mark) {
        l = app_play_continue_sbc_more_data((uint8_t *)app_play_sbc_cache,
                                            len / 2);
      } else {
        l = app_play_single_sbc_more_data((uint8_t *)app_play_sbc_cache,
                                          len / 2);
      }
      if (l != len / 2) {
        memset(app_play_sbc_cache + l, 0, len / 2 - l);
        app_play_lineinmode_merge = 0;
      }
      app_play_audio_lineinmode_stereo_merge(
          (int16_t *)buf, (int16_t *)app_play_sbc_cache, len / 2);
    }
  }

  return l;
}

int app_play_audio_lineinmode_init(uint8_t mode, uint32_t buff_len) {
  TRACE(1, "lapp_play_audio_lineinmode_init:%d ", buff_len);
  app_play_lineinmode_mode = mode;
  app_audio_mempool_get_buff((uint8_t **)&app_play_sbc_cache, buff_len);
  media_audio_init();
  return 0;
}

int app_play_audio_lineinmode_start(APP_AUDIO_STATUS *status) {
  if (app_play_audio_sample_rate == AUD_SAMPRATE_44100) {
    LOCK_APP_AUDIO_QUEUE();
    APP_AUDIO_DeCQueue(&media_sbc_queue, 0,
                       APP_AUDIO_LengthOfCQueue(&media_sbc_queue));
    UNLOCK_APP_AUDIO_QUEUE();
    app_play_lineinmode_merge = 1;
    need_init_decoder = 1;
    media_Play_init_audio(status->aud_id);
  }
  return 0;
}

int app_play_audio_lineinmode_stop(APP_AUDIO_STATUS *status) {
  app_play_lineinmode_merge = 0;
  return 0;
}
#endif

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
#define DELAY_SAMPLE_MC (33 * 2) //  2:ch
static int32_t delay_buf_media[DELAY_SAMPLE_MC];
static uint32_t audio_mc_data_playback_media(uint8_t *buf,
                                             uint32_t mc_len_bytes) {
  uint32_t begin_time;
  // uint32_t end_time;
  begin_time = hal_sys_timer_get();
  TRACE_MEDIA_PLAYESTREAM_I("[PLAYBACK_MEDIA][MC] %d", begin_time);

  float left_gain;
  float right_gain;
  int32_t playback_len_bytes, mc_len_bytes_8;
  int32_t i, j, k;
  int delay_sample;

  mc_len_bytes_8 = mc_len_bytes / 8;

  hal_codec_get_dac_gain(&left_gain, &right_gain);

  // TRACE_MEDIA_PLAYESTREAM_I("playback_samplerate_ratio:
  // %d",playback_samplerate_ratio);

  // TRACE_MEDIA_PLAYESTREAM_I("left_gain:  %d",(int)(left_gain*(1<<12)));
  // TRACE_MEDIA_PLAYESTREAM_I("right_gain: %d",(int)(right_gain*(1<<12)));

  playback_len_bytes = mc_len_bytes / playback_samplerate_ratio_bt;

  if (sample_size_play_bt == AUD_BITS_16) {
    int16_t *sour_p = (int16_t *)(playback_buf_bt + playback_size_bt / 2);
    int16_t *mid_p = (int16_t *)(buf);
    int16_t *mid_p_8 = (int16_t *)(buf + mc_len_bytes - mc_len_bytes_8);
    int16_t *dest_p = (int16_t *)buf;

    if (buf == playback_buf_mc) {
      sour_p = (int16_t *)playback_buf_bt;
    }

    delay_sample = DELAY_SAMPLE_MC;

    for (i = 0, j = 0; i < delay_sample; i = i + 2) {
      mid_p[j++] = delay_buf_media[i];
      mid_p[j++] = delay_buf_media[i + 1];
    }

    for (i = 0; i < playback_len_bytes / 2 - delay_sample; i = i + 2) {
      mid_p[j++] = sour_p[i];
      mid_p[j++] = sour_p[i + 1];
    }

    for (j = 0; i < playback_len_bytes / 2; i = i + 2) {
      delay_buf_media[j++] = sour_p[i];
      delay_buf_media[j++] = sour_p[i + 1];
    }

    if (playback_samplerate_ratio_bt <= 8) {
      for (i = 0, j = 0; i < playback_len_bytes / 2;
           i = i + 2 * (8 / playback_samplerate_ratio_bt)) {
        mid_p_8[j++] = mid_p[i];
        mid_p_8[j++] = mid_p[i + 1];
      }
    } else {
      for (i = 0, j = 0; i < playback_len_bytes / 2; i = i + 2) {
        for (k = 0; k < playback_samplerate_ratio_bt / 8; k++) {
          mid_p_8[j++] = mid_p[i];
          mid_p_8[j++] = mid_p[i + 1];
        }
      }
    }

    anc_mc_run_stereo((uint8_t *)mid_p_8, mc_len_bytes_8, left_gain, right_gain,
                      AUD_BITS_16);

    for (i = 0, j = 0; i < (mc_len_bytes_8) / 2; i = i + 2) {
      for (k = 0; k < 8; k++) {
        dest_p[j++] = mid_p_8[i];
        dest_p[j++] = mid_p_8[i + 1];
      }
    }

  } else if (sample_size_play_bt == AUD_BITS_24) {
    int32_t *sour_p = (int32_t *)(playback_buf_bt + playback_size_bt / 2);
    int32_t *mid_p = (int32_t *)(buf);
    int32_t *mid_p_8 = (int32_t *)(buf + mc_len_bytes - mc_len_bytes_8);
    int32_t *dest_p = (int32_t *)buf;

    if (buf == (playback_buf_mc)) {
      sour_p = (int32_t *)playback_buf_bt;
    }

    delay_sample = DELAY_SAMPLE_MC;

    for (i = 0, j = 0; i < delay_sample; i = i + 2) {
      mid_p[j++] = delay_buf_media[i];
      mid_p[j++] = delay_buf_media[i + 1];
    }

    for (i = 0; i < playback_len_bytes / 4 - delay_sample; i = i + 2) {
      mid_p[j++] = sour_p[i];
      mid_p[j++] = sour_p[i + 1];
    }

    for (j = 0; i < playback_len_bytes / 4; i = i + 2) {
      delay_buf_media[j++] = sour_p[i];
      delay_buf_media[j++] = sour_p[i + 1];
    }

    if (playback_samplerate_ratio_bt <= 8) {
      for (i = 0, j = 0; i < playback_len_bytes / 4;
           i = i + 2 * (8 / playback_samplerate_ratio_bt)) {
        mid_p_8[j++] = mid_p[i];
        mid_p_8[j++] = mid_p[i + 1];
      }
    } else {
      for (i = 0, j = 0; i < playback_len_bytes / 4; i = i + 2) {
        for (k = 0; k < playback_samplerate_ratio_bt / 8; k++) {
          mid_p_8[j++] = mid_p[i];
          mid_p_8[j++] = mid_p[i + 1];
        }
      }
    }

    anc_mc_run_stereo((uint8_t *)mid_p_8, mc_len_bytes_8, left_gain, right_gain,
                      AUD_BITS_24);

    for (i = 0, j = 0; i < (mc_len_bytes_8) / 4; i = i + 2) {
      for (k = 0; k < 8; k++) {
        dest_p[j++] = mid_p_8[i];
        dest_p[j++] = mid_p_8[i + 1];
      }
    }
  }

  //  end_time = hal_sys_timer_get();

  //   TRACE_MEDIA_PLAYESTREAM_I("%s:run time: %d", __FUNCTION__,
  //   end_time-begin_time);

  return 0;
}
#endif

void app_audio_playback_done(void) {
#if defined(IBRT)
  app_tws_sync_prompt_check();
#endif
}

int app_play_audio_stop(void) {
  TRACE_MEDIA_PLAYESTREAM_I("[STOP]");

  app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE, 0);
  return 0;
}

uint32_t g_active_aud_id = MAX_RECORD_NUM;

int app_play_audio_set_aud_id(uint32_t aud_id) {
  g_active_aud_id = aud_id;
  return 0;
}

int app_play_audio_get_aud_id(void) { return g_active_aud_id; }

void app_play_audio_set_lang(int L) { g_language = L; }

int app_play_audio_get_lang() { return g_language; }
extern struct BT_DEVICE_T app_bt_device;
int app_play_audio_onoff(bool onoff, APP_AUDIO_STATUS *status) {
  static bool isRun = false;

  struct AF_STREAM_CONFIG_T stream_cfg;
  uint8_t *bt_audio_buff = NULL;
  uint16_t bytes_parsed = 0;
  enum AUD_SAMPRATE_T sample_rate POSSIBLY_UNUSED = AUD_SAMPRATE_16000;
  uint16_t aud_id = 0;
  uint16_t aud_pram = 0;

  TRACE_MEDIA_PLAYESTREAM_I("[MEDIA_ONOFF] %s, to %s it",
                            isRun ? "Running" : "Idle",
                            onoff ? "start" : "stop");

  if (isRun == onoff) {
    return 0;
  }
  if (onoff) {

#ifdef WL_DET
    app_mic_alg_audioloop(false, APP_SYSFREQ_78M);
#endif

#if defined(__AI_VOICE__) || defined(BISTO_ENABLED)
    app_ai_if_inform_music_or_prompt_status(true, AUD_SAMPRATE_16000);
    app_ai_if_pre_music_or_prompt_check();
#endif

#if defined(__THIRDPARTY)
    app_thirdparty_specific_lib_event_handle(THIRDPARTY_FUNC_NO1,
                                             THIRDPARTY_STOP);
#endif
    aud_id = PROMPT_ID_FROM_ID_VALUE(status->aud_id);
    aud_pram = PROMPT_PRAM_FROM_ID_VALUE(status->aud_id);
    g_prompt_chnlsel = PROMPT_CHNLSEl_FROM_ID_VALUE(aud_pram);
    TRACE_MEDIA_PLAYESTREAM_I(
        "[MEDIA_ONOFF] aud_id:%04x %s aud_pram:%04x chnlsel:%d", status->aud_id,
        aud_id2str(aud_id), aud_pram, g_prompt_chnlsel);

    media_Play_init_audio(aud_id);
    app_play_audio_set_aud_id(aud_id);
    if (!g_app_audio_length) {
      app_audio_sendrequest(APP_PLAY_BACK_AUDIO, (uint8_t)APP_BT_SETTING_CLOSE,
                            0);
      return 0;
    }

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_104M);
#else
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_52M);
#endif
    af_set_priority(AF_USER_AUDIO, osPriorityHigh);
    app_audio_mempool_init_with_specific_size(APP_AUDIO_BUFFER_SIZE);
    media_audio_init();

#if (defined(APP_LINEIN_A2DP_SOURCE) || defined(APP_I2S_A2DP_SOURCE)) &&       \
    defined(ENHANCED_STACK)
    if (app_bt_device.src_or_snk == BT_DEVICE_SRC) {
      app_a2dp_source_init();
    }
#endif

    btif_sbc_init_decoder(media_sbc_decoder);
    btif_sbc_decode_frames(media_sbc_decoder, g_app_audio_data,
                           g_app_audio_length, &bytes_parsed, NULL, 0, NULL);
    switch (media_sbc_decoder->streamInfo.sampleFreq) {
    case BTIF_SBC_CHNL_SAMPLE_FREQ_16:
      sample_rate = AUD_SAMPRATE_16000;
      break;
    case BTIF_SBC_CHNL_SAMPLE_FREQ_32:
      sample_rate = AUD_SAMPRATE_32000;
      break;
    case BTIF_SBC_CHNL_SAMPLE_FREQ_44_1:
      sample_rate = AUD_SAMPRATE_44100;
      break;
    case BTIF_SBC_CHNL_SAMPLE_FREQ_48:
      sample_rate = AUD_SAMPRATE_48000;
      break;
    default:
      sample_rate = AUD_SAMPRATE_16000;
      break;
    }

#ifdef PLAYBACK_USE_I2S
    hal_cmu_audio_resample_disable();
#endif

    memset(&stream_cfg, 0, sizeof(stream_cfg));

#if defined(MEDIA_PLAY_24BIT)
    stream_cfg.bits = AUD_BITS_24;
#else
    stream_cfg.bits = AUD_BITS_16;
#endif
    stream_cfg.channel_num = AUD_CHANNEL_NUM_2;
#ifdef __BT_ANC__
    stream_cfg.sample_rate = AUD_SAMPRATE_48000;
#else
    stream_cfg.sample_rate = AUD_SAMPRATE_16000;
#endif
#ifdef PLAYBACK_USE_I2S
    stream_cfg.device = AUD_STREAM_USE_I2S0_MASTER;
    stream_cfg.io_path = AUD_IO_PATH_NULL;
#else
    stream_cfg.device = AUD_STREAM_USE_INT_CODEC;
    stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;
#endif
#ifdef __INTERACTION__
    if (aud_id == AUD_ID_BT_FINDME) {
      stream_cfg.vol = g_findme_fadein_vol;
    } else
#endif
    {
      stream_cfg.vol = TGT_VOLUME_LEVEL_WARNINGTONE;
    }
    stream_cfg.handler = app_play_sbc_more_data;

    stream_cfg.data_size = APP_AUDIO_PLAYBACK_BUFF_SIZE;

#if defined(MEDIA_PLAY_24BIT)
    stream_cfg.data_size *= 2;
#endif

    g_cache_buff_sz = stream_cfg.data_size / 2 / 2;

    app_audio_mempool_get_buff((uint8_t **)&app_play_sbc_cache,
                               g_cache_buff_sz);
    app_audio_mempool_get_buff(&bt_audio_buff, stream_cfg.data_size);
    stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(bt_audio_buff);

#ifdef __BT_ANC__
    bt_sco_samplerate_ratio = 3;
    us_fir_init();
#endif

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
    sample_size_play_bt = stream_cfg.bits;
    sample_rate_play_bt = stream_cfg.sample_rate;
    data_size_play_bt = stream_cfg.data_size;
    playback_buf_bt = stream_cfg.data_ptr;
    playback_size_bt = stream_cfg.data_size;
#ifdef __BT_ANC__
    playback_samplerate_ratio_bt = 8;
#else
    playback_samplerate_ratio_bt = 8 * 3;
#endif
    playback_ch_num_bt = stream_cfg.channel_num;
#endif
    af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg);

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
    stream_cfg.bits = sample_size_play_bt;
    stream_cfg.channel_num = playback_ch_num_bt;
    stream_cfg.sample_rate = sample_rate_play_bt;
    stream_cfg.device = AUD_STREAM_USE_MC;
    stream_cfg.vol = 0;
    stream_cfg.handler = audio_mc_data_playback_media;
    stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER;

    app_audio_mempool_get_buff(
        &bt_audio_buff, data_size_play_bt * playback_samplerate_ratio_bt);
    stream_cfg.data_ptr = BT_AUDIO_CACHE_2_UNCACHE(bt_audio_buff);
    stream_cfg.data_size = data_size_play_bt * playback_samplerate_ratio_bt;

    playback_buf_mc = stream_cfg.data_ptr;
    playback_size_mc = stream_cfg.data_size;

    anc_mc_run_init(hal_codec_anc_convert_rate(sample_rate_play_bt));
    af_stream_open(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, &stream_cfg);
#endif

#if !(defined(__AUDIO_RESAMPLE__) && defined(SW_PLAYBACK_RESAMPLE))
    af_codec_tune(AUD_STREAM_NUM, 0);
#endif

#if defined(IBRT)
    app_ibrt_voice_report_trigger_init(aud_id, aud_pram);
#endif
    af_stream_start(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
    af_stream_start(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK);
#endif

  } else {

#ifdef VOICE_DATAPATH
    app_voicepath_set_stream_state(AUDIO_OUTPUT_STREAMING, false);
    app_voicepath_set_pending_started_stream(AUDIO_OUTPUT_STREAMING, false);
#endif
#if !(defined(__AUDIO_RESAMPLE__) && defined(SW_PLAYBACK_RESAMPLE))
    af_codec_tune(AUD_STREAM_PLAYBACK, 0);
#endif

    af_stream_stop(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);
    af_stream_close(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK);

#if defined(AUDIO_ANC_FB_MC_MEDIA) && defined(ANC_APP) &&                      \
    !defined(__AUDIO_RESAMPLE__)
    af_stream_stop(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK);
    af_stream_close(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK);
#endif
#if defined(IBRT)
    app_ibrt_voice_report_trigger_deinit();
#ifdef MIX_AUDIO_PROMPT_WITH_A2DP_MEDIA_ENABLED
    audio_prompt_stop_playing();
#endif
#endif
#ifdef PLAYBACK_USE_I2S
    hal_cmu_audio_resample_enable();
#endif

    app_play_sbc_cache = NULL;
    g_cache_buff_sz = 0;
    g_prompt_chnlsel = PROMOT_ID_BIT_MASK_CHNLSEl_ALL;
    app_play_audio_set_aud_id(MAX_RECORD_NUM);
    af_set_priority(AF_USER_AUDIO, osPriorityAboveNormal);
    app_sysfreq_req(APP_SYSFREQ_USER_APP_0, APP_SYSFREQ_32K);

    app_audio_playback_done();
#if defined(__THIRDPARTY)
    app_thirdparty_specific_lib_event_handle(THIRDPARTY_FUNC_NO1,
                                             THIRDPARTY_START);
#endif

#ifdef WL_DET
    app_mic_alg_audioloop(true, APP_SYSFREQ_78M);
#endif
  }
  isRun = onoff;

  return 0;
}

static void app_stop_local_prompt_playing(void) {
  app_audio_sendrequest(APP_PLAY_BACK_AUDIO, APP_BT_SETTING_CLOSE, 0);
#ifdef MIX_AUDIO_PROMPT_WITH_A2DP_MEDIA_ENABLED
  audio_prompt_stop_playing();
#endif
}

void app_stop_both_prompt_playing(void) {
  app_stop_local_prompt_playing();
  app_tws_stop_peer_prompt();
}

void app_tws_cmd_stop_prompt_handler(uint8_t *ptrParam, uint16_t paramLen) {
  TRACE_MEDIA_PLAYESTREAM_I("[STOP_PROMPT_HANDLER]");
  app_stop_local_prompt_playing();
}
#endif
