/******************************************************************************
 *                                                                            *
 * Copyright (C) 2018 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 *****************************************************************************
 * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>

#include <ixheaacd_type_def.h>

#include "ixheaacd_cnst.h"

#include "ixheaacd_bitbuffer.h"
#include "ixheaacd_config.h"
#include "ixheaacd_interface.h"
#include "ixheaacd_acelp_info.h"

#include "ixheaacd_tns_usac.h"
#include "ixheaacd_sbrdecsettings.h"
#include "ixheaacd_info.h"
#include "ixheaacd_struct.h"
#include "ixheaacd_sbr_common.h"
#include "ixheaacd_drc_data_struct.h"
#include "ixheaacd_drc_dec.h"

#include "ixheaacd_sbr_scale.h"
#include "ixheaacd_env_extr_part.h"
#include "ixheaacd_sbr_rom.h"
#include "ixheaacd_hybrid.h"
#include "ixheaacd_ps_dec.h"
#include "ixheaacd_common_rom.h"
#include "ixheaacd_qmf_dec.h"
#include "ixheaacd_sbr_const.h"
#include "ixheaacd_lpp_tran.h"
#include "ixheaacd_sbrdecoder.h"
#include "ixheaacd_env_extr.h"
#include "ixheaacd_env_calc.h"
#include "ixheaacd_pvc_dec.h"
#include "ixheaacd_sbr_dec.h"
#include "ixheaacd_mps_polyphase.h"
#include "ixheaacd_sbr_const.h"

#include "ixheaacd_main.h"

#include "ixheaacd_arith_dec.h"

#include <ixheaacd_type_def.h>
#include "ixheaacd_memory_standards.h"
#include "ixheaacd_sbrdecsettings.h"
#include "ixheaacd_defines.h"
#include <ixheaacd_aac_rom.h>
#include "ixheaacd_common_rom.h"
#include <ixheaacd_sbr_rom.h>
#include "ixheaacd_bitbuffer.h"
#include "ixheaacd_pulsedata.h"
#include "ixheaacd_pns.h"

#include "ixheaacd_lt_predict.h"

#include "ixheaacd_channelinfo.h"
#include "ixheaacd_channel.h"
#include "ixheaacd_channelinfo.h"
#include "ixheaacd_sbrdecoder.h"
#include "ixheaacd_audioobjtypes.h"
#include "ixheaacd_latmdemux.h"
#include "ixheaacd_aacdec.h"
#include "ixheaacd_sbr_common.h"

#include "ixheaacd_mps_polyphase.h"
#include "ixheaacd_config.h"
#include "ixheaacd_mps_dec.h"
#include "ixheaacd_struct_def.h"

#include "ixheaacd_create.h"

#include "ixheaacd_process.h"

#include "ixheaacd_sbrdecoder.h"

#include "ixheaacd_mps_interface.h"

#include "ixheaacd_bit_extract.h"
#include "ixheaacd_func_def.h"
#include "ixheaacd_interface.h"

extern ia_huff_code_word_struct ixheaacd_huff_book_scl[];

extern WORD32 ixheaacd_book_scl_index[];
extern WORD16 ixheaacd_book_scl_code_book[];

extern ia_usac_samp_rate_info ixheaacd_samp_rate_info[];
extern const WORD32 ixheaacd_sampling_boundaries[(1 << LEN_SAMP_IDX)];

const WORD32 ixheaacd_sampl_freq_idx_table[17] = {
    96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050, 16000,
    12000, 11025, 8000,  7350,  -1,    -1,    -1,    -1};

static VOID ixheaacd_info_init(ia_usac_samp_rate_info *ptr_samp_info,
                               WORD32 block_size_samples,
                               ia_sfb_info_struct *pstr_sfb_info_long,
                               ia_sfb_info_struct *pstr_sfb_info_short,
                               WORD16 *sfb_width_short,
                               WORD16 *sfb_width_long) {
  WORD32 i, j, k, n, ws;
  const WORD16 *sfbands;
  ia_sfb_info_struct *pstr_sfb_info_ip;

  pstr_sfb_info_long->islong = 1;
  pstr_sfb_info_long->max_win_len = 1;
  pstr_sfb_info_long->samp_per_bk = block_size_samples;

  switch (block_size_samples) {
    case 480:
      pstr_sfb_info_long->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_480;
      pstr_sfb_info_long->sfb_per_sbk = ptr_samp_info->num_sfb_480;
      break;
    case 512:
      pstr_sfb_info_long->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_512;
      pstr_sfb_info_long->sfb_per_sbk = ptr_samp_info->num_sfb_512;
      break;
    case 768:
      pstr_sfb_info_long->sfb_per_sbk = ptr_samp_info->num_sfb_768;
      pstr_sfb_info_long->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_768;
      break;
    case 960:
      pstr_sfb_info_long->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_960;
      pstr_sfb_info_long->sfb_per_sbk = ptr_samp_info->num_sfb_960;
      break;
    case 1024:
      pstr_sfb_info_long->sfb_per_sbk = ptr_samp_info->num_sfb_1024;
      pstr_sfb_info_long->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_1024;
      break;
    default:
      assert(0);
      break;
  }

  pstr_sfb_info_long->sfb_width = sfb_width_long;
  pstr_sfb_info_long->num_groups = 1;
  pstr_sfb_info_long->group_len[0] = 1;

  for (i = 0, j = 0, n = pstr_sfb_info_long->sfb_per_sbk; i < n; i++) {
    k = pstr_sfb_info_long->ptr_sfb_tbl[i];
    pstr_sfb_info_long->sfb_width[i] = k - j;
    j = k;
  }

  pstr_sfb_info_short->islong = 0;
  pstr_sfb_info_short->max_win_len = NSHORT;
  pstr_sfb_info_short->samp_per_bk = block_size_samples;

  for (i = 0; i < pstr_sfb_info_short->max_win_len; i++) {
    switch (block_size_samples) {
      case 768:
        pstr_sfb_info_short->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_96;
        pstr_sfb_info_short->sfb_per_sbk = ptr_samp_info->num_sfb_96;
        break;
      case 960:
        pstr_sfb_info_short->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_120;
        pstr_sfb_info_short->sfb_per_sbk = ptr_samp_info->num_sfb_120;
        break;
      case 1024:
        pstr_sfb_info_short->ptr_sfb_tbl = ptr_samp_info->ptr_sfb_128;
        pstr_sfb_info_short->sfb_per_sbk = ptr_samp_info->num_sfb_128;
        break;
      default:
        assert(0);
        break;
    }
  }

  pstr_sfb_info_short->sfb_width = sfb_width_short;
  for (i = 0, j = 0, n = pstr_sfb_info_short->sfb_per_sbk; i < n; i++) {
    k = pstr_sfb_info_short->ptr_sfb_tbl[i];
    pstr_sfb_info_short->sfb_width[i] = k - j;
    j = k;
  }

  pstr_sfb_info_ip = pstr_sfb_info_long;
  for (ws = 0; ws < 2; ws++) {
    pstr_sfb_info_ip->sfb_per_bk = 0;
    k = 0;
    n = 0;
    for (i = 0; i < pstr_sfb_info_ip->max_win_len; i++) {
      pstr_sfb_info_ip->bins_per_sbk =
          pstr_sfb_info_ip->samp_per_bk / pstr_sfb_info_ip->max_win_len;

      pstr_sfb_info_ip->sfb_per_bk += pstr_sfb_info_ip->sfb_per_sbk;

      sfbands = pstr_sfb_info_ip->ptr_sfb_tbl;
      for (j = 0; j < pstr_sfb_info_ip->sfb_per_sbk; j++)
        pstr_sfb_info_ip->sfb_idx_tbl[j + k] = sfbands[j] + n;

      n += pstr_sfb_info_ip->bins_per_sbk;
      k += pstr_sfb_info_ip->sfb_per_sbk;
    }
    pstr_sfb_info_ip = pstr_sfb_info_short;
  }
}

WORD32 ixheaacd_decode_init(
    VOID *handle, WORD32 sample_rate, ia_usac_data_struct *usac_data,
    ia_audio_specific_config_struct *pstr_stream_config) {
  WORD32 i;
  ia_exhaacplus_dec_api_struct *codec_handle =
      (ia_exhaacplus_dec_api_struct *)handle;
  ia_aac_dec_state_struct *aac_dec_handle = codec_handle->p_state_aac;
  WORD32 fscale;

  WORD32 ele_id = 0;

  ia_usac_config_struct *ptr_usac_config =
      &(pstr_stream_config->str_usac_config);
  ia_usac_decoder_config_struct *ptr_usac_dec_config =
      &(pstr_stream_config->str_usac_config.str_usac_dec_config);
  WORD32 num_elements = ptr_usac_dec_config->num_elements;
  WORD32 chan = 0;

  usac_data->huffman_code_book_scl = aac_dec_handle->huffman_code_book_scl;
  usac_data->huffman_code_book_scl_index =
      aac_dec_handle->huffman_code_book_scl_index;

  usac_data->tns_coeff3_32 =
      aac_dec_handle->pstr_aac_tables->pstr_block_tables->tns_coeff3_32;
  usac_data->tns_coeff4_32 =
      aac_dec_handle->pstr_aac_tables->pstr_block_tables->tns_coeff4_32;
  usac_data->tns_max_bands_tbl_usac =
      &aac_dec_handle->pstr_aac_tables->pstr_block_tables
           ->tns_max_bands_tbl_usac;

  for (i = 0; i < 11; i++) {
    if (ixheaacd_sampling_boundaries[i] <= sample_rate) break;
  }

  if (i == (1 << LEN_SAMP_IDX)) return -1;
  usac_data->sampling_rate_idx = i;

  fscale = (WORD32)((double)sample_rate * (double)FSCALE_DENOM / 12800.0f);

  for (i = 0; i < MAX_NUM_CHANNELS; i++) {
    usac_data->window_shape_prev[i] = 0;
    usac_data->window_shape[i] = 0;
  }

  ixheaacd_hufftab(&ixheaacd_book, ixheaacd_huff_book_scl,
                   ixheaacd_book_scl_code_book, ixheaacd_book_scl_index, 1, 60,
                   60, 1, 19);

  usac_data->pstr_usac_winmap[0] = &usac_data->str_only_long_info;
  usac_data->pstr_usac_winmap[1] = &usac_data->str_only_long_info;
  usac_data->pstr_usac_winmap[2] = &usac_data->str_eight_short_info;
  usac_data->pstr_usac_winmap[3] = &usac_data->str_only_long_info;
  usac_data->pstr_usac_winmap[4] = &usac_data->str_only_long_info;

  if ((usac_data->ccfl != 480) && (usac_data->ccfl != 512) &&
      (usac_data->ccfl != 768) && (usac_data->ccfl != 960) &&
      (usac_data->ccfl != 1024))
    return -1;
  ixheaacd_info_init(&ixheaacd_samp_rate_info[usac_data->sampling_rate_idx],
                     usac_data->ccfl, usac_data->pstr_usac_winmap[0],
                     usac_data->pstr_usac_winmap[2], usac_data->sfb_width_short,
                     usac_data->sfb_width_long);

  for (i = 0; i < MAX_NUM_CHANNELS; i++) {
    usac_data->str_tddec[i] = &usac_data->arr_str_tddec[i];
    usac_data->str_tddec[i]->fscale =
        ((fscale)*usac_data->ccfl) / LEN_SUPERFRAME;
    usac_data->len_subfrm = usac_data->ccfl / 4;
    usac_data->num_subfrm = (MAX_NUM_SUBFR * usac_data->ccfl) / LEN_SUPERFRAME;

    ixheaacd_init_acelp_data(usac_data, usac_data->str_tddec[i]);

    usac_data->str_tddec[i]->fd_synth =
        &usac_data->str_tddec[i]->fd_synth_buf[LEN_FRAME];
  }

  for (ele_id = 0; ele_id < num_elements; ele_id++) {
    UWORD32 ele_type;
    WORD32 stereo_config_index;

    ia_usac_dec_element_config_struct *ptr_usac_ele_config =
        &ptr_usac_config->str_usac_dec_config.str_usac_element_config[ele_id];

    if (ptr_usac_ele_config) {
      if (usac_data->tw_mdct[ele_id]) {
        return -1;
      }

      usac_data->noise_filling_config[ele_id] =
          ptr_usac_ele_config->noise_filling;
    }

    ele_type = ptr_usac_config->str_usac_dec_config.usac_element_type[ele_id];

    stereo_config_index = ptr_usac_ele_config->stereo_config_index;

    switch (ele_type) {
      case ID_USAC_SCE:
      case ID_USAC_LFE:

        if ((chan + 1) > MAX_NUM_CHANNELS_USAC_LVL2) return -1;
        usac_data->seed_value[chan] = 0x3039;
        chan++;

        break;

      case ID_USAC_CPE: {
        static const WORD32 frame_len_tbl[MAX_CORE_SBR_FRAME_LEN_IDX + 1] = {
            -1, -1, 32, 32, 64};

        if ((chan + 2) > MAX_NUM_CHANNELS_USAC_LVL2) return -1;
        usac_data->seed_value[chan] = 0x3039;
        chan++;

        usac_data->seed_value[chan] = 0x10932;
        chan++;

        if (stereo_config_index > 0) {
          WORD32 bs_frame_length =
              frame_len_tbl[ptr_usac_config->core_sbr_framelength_index];
          WORD32 bs_residual_coding = (stereo_config_index > 1) ? 1 : 0;

          ia_usac_dec_mps_config_struct *ptr_usac_mps212_config =
              &(ptr_usac_config->str_usac_dec_config
                    .str_usac_element_config[ele_id]
                    .str_usac_mps212_config);

          if (ixheaacd_mps_create(&aac_dec_handle->mps_dec_handle,
                                  bs_frame_length, bs_residual_coding,
                                  ptr_usac_mps212_config)) {
            return -1;
          }
        }
        break;
      }

      break;
      case ID_USAC_EXT:
        break;
      default:
        return -1;
        break;
    }
  }

  return 0;
}

WORD32 ixheaacd_dec_data_init(VOID *handle,
                              ia_frame_data_struct *pstr_frame_data,
                              ia_usac_data_struct *usac_data) {
  ia_audio_specific_config_struct *pstr_stream_config, *layer_config;
  WORD32 err_code = 0;

  WORD32 num_out_chan = 0;

  WORD32 i_ch, i, ele_id;
  WORD32 num_elements;

  WORD32 out_frame_len, sbr_ratio_idx;

  ia_usac_config_struct *ptr_usac_config =
      &(pstr_frame_data->str_audio_specific_config.str_usac_config);

  usac_data->window_shape_prev[0] = WIN_SEL_0;
  usac_data->window_shape_prev[1] = WIN_SEL_0;

  pstr_frame_data->str_layer.bit_rate =
      pstr_frame_data->str_audio_specific_config.avg_bit_rate;
  pstr_stream_config = &pstr_frame_data->str_audio_specific_config;
  layer_config = &pstr_frame_data->str_audio_specific_config;

  sbr_ratio_idx = ixheaacd_sbr_params(
      ptr_usac_config->core_sbr_framelength_index, &out_frame_len,
      &usac_data->ccfl, &usac_data->output_samples,
      &pstr_frame_data->str_layer.sample_rate_layer,
      &layer_config->samp_frequency_index);

  pstr_stream_config->sampling_frequency =
      pstr_frame_data->str_layer.sample_rate_layer;
  pstr_stream_config->samp_frequency_index = layer_config->samp_frequency_index;

  num_elements = ptr_usac_config->str_usac_dec_config.num_elements;

  for (ele_id = 0; ele_id < num_elements; ele_id++) {
    ia_usac_dec_element_config_struct *ptr_usac_ele_config =
        &(ptr_usac_config->str_usac_dec_config.str_usac_element_config[ele_id]);

    if (ptr_usac_ele_config) {
      usac_data->tw_mdct[ele_id] = ptr_usac_ele_config->tw_mdct;
    }

    {
      ia_usac_dec_mps_config_struct *ptr_usac_mps212_config =
          &ptr_usac_ele_config->str_usac_mps212_config;
      WORD32 stereo_config_index = ptr_usac_ele_config->stereo_config_index;

      usac_data->mps_pseudo_lr[ele_id] =
          (stereo_config_index > 1) ? ptr_usac_mps212_config->bs_pseudo_lr : 0;
    }
  }

  usac_data->sbr_ratio_idx = sbr_ratio_idx;
  usac_data->esbr_bit_str[0].no_elements = 0;
  usac_data->esbr_bit_str[1].no_elements = 0;

  num_out_chan = ptr_usac_config->num_out_channels;

  if (usac_data->ccfl == 768)
    pstr_frame_data->str_layer.sample_rate_layer =
        4 * pstr_frame_data->str_layer.sample_rate_layer / 3;

  for (i = 0; i < MAX_NUM_CHANNELS; i++) {
    usac_data->coef_fix[i] = &usac_data->arr_coef_fix[i][0];
    usac_data->coef[i] = &usac_data->arr_coef[i][0];
    usac_data->coef_save[i] = &usac_data->arr_coef_save[i][0];
    usac_data->factors[i] = &usac_data->arr_factors[i][0];
    usac_data->group_dis[i] = &usac_data->arr_group_dis[i][0];
    usac_data->pstr_tns[i] = &usac_data->arr_str_tns[i];
    usac_data->tw_ratio[i] = &usac_data->arr_tw_ratio[i][0];
    usac_data->ms_used[i] = &usac_data->arr_ms_used[i][0];
    usac_data->window_shape_prev[i] = WIN_SEL_0;

    usac_data->seed_value[i] = 0x0;

    usac_data->fac_data_present[i] = 0;
  }

  err_code =
      ixheaacd_decode_init(handle, pstr_frame_data->str_layer.sample_rate_layer,
                           usac_data, pstr_stream_config);
  if (err_code != 0) return err_code;

  for (i_ch = 0; i_ch < MAX_NUM_CHANNELS; i_ch++) {
    if (usac_data->tw_mdct[0] == 1) {
      WORD32 i;
      for (i = 0; i < 2 * usac_data->ccfl; i++) {
        usac_data->warp_cont_mem[i_ch][i] = 1.0;
      }
      usac_data->warp_sum[i_ch][0] = usac_data->warp_sum[i_ch][1] =
          (FLOAT32)usac_data->ccfl;
    }
  }
  return err_code;
}

static VOID ixheaacd_count_tracks_per_layer(int *max_layer, int *stream_count,
                                            int *tracks_in_layer) {
  WORD32 stream;
  WORD32 num_layer;
  WORD32 num_streams;
  WORD32 layer = 0;

  if (stream_count == NULL)
    num_streams = 0;
  else
    num_streams = *stream_count;
  if (max_layer == NULL)
    num_layer = num_streams;
  else
    num_layer = *max_layer;
  if (num_layer < 0) num_layer = num_streams;

  for (stream = 0; (layer <= num_layer) && (stream < num_streams);) {
    *tracks_in_layer = 1;
    stream += 1;
    layer++;
    if (layer <= num_layer) *tracks_in_layer = 0;
  }

  if (max_layer) *max_layer = (layer - 1);
  if (stream_count) *stream_count = stream;
}

WORD32 ixheaacd_frm_data_init(ia_audio_specific_config_struct *pstr_audio_conf,
                              ia_dec_data_struct *pstr_dec_data)

{
  WORD32 layer;
  WORD32 track;
  WORD32 num_dec_streams;
  ia_frame_data_struct *pstr_frame_data;

  WORD32 stream_count = 1;
  WORD32 max_layer = -1;

  memset(pstr_dec_data, 0, sizeof(ia_dec_data_struct));
  memset(&(pstr_dec_data->str_frame_data), 0,
         sizeof(pstr_dec_data->str_frame_data));

  pstr_frame_data = &(pstr_dec_data->str_frame_data);

  if (max_layer < 0) max_layer = stream_count - 1;

  ixheaacd_count_tracks_per_layer(&max_layer, &stream_count,
                                  &pstr_frame_data->tracks_in_layer);

  pstr_frame_data->scal_out_select = max_layer;

  pstr_frame_data->stream_count = 0;

  num_dec_streams = track = 0;
  for (layer = 0; layer < (signed)pstr_frame_data->scal_out_select + 1;
       layer++) {
    WORD32 j;
    for (j = 0; j < 1; j++, num_dec_streams++) {
      pstr_frame_data->str_audio_specific_config = *pstr_audio_conf;
      pstr_frame_data->str_layer.sample_rate_layer =
          pstr_frame_data->str_audio_specific_config.sampling_frequency;
      pstr_frame_data->str_layer.bit_rate =
          pstr_frame_data->str_audio_specific_config.avg_bit_rate;
    }

    track += pstr_frame_data->tracks_in_layer;
  }

  pstr_frame_data->stream_count = num_dec_streams;

  return num_dec_streams;
}

WORD32 ixheaacd_decode_create(ia_exhaacplus_dec_api_struct *handle,
                              ia_dec_data_struct *pstr_dec_data,
                              WORD32 tracks_for_decoder) {
  WORD32 stream;

  WORD32 err = 0;
  ia_frame_data_struct *pstr_frame_data;
  WORD32 stream_count;
  ia_aac_dec_state_struct *aac_dec_handle = handle->p_state_aac;
  pstr_frame_data = &(pstr_dec_data->str_frame_data);
  stream_count = pstr_frame_data->stream_count;
  pstr_frame_data->stream_count = tracks_for_decoder;

  for (stream = 0; stream < stream_count; stream++) {
    UWORD32 aot = pstr_frame_data->str_audio_specific_config.audio_object_type;

    switch (aot) {
      case AOT_USAC:

        err = ixheaacd_dec_data_init(handle, pstr_frame_data,
                                     &(pstr_dec_data->str_usac_data));

        if (err != 0) return err;

        switch (pstr_dec_data->str_usac_data.sbr_ratio_idx) {
          case 0:
            handle->aac_config.ui_sbr_mode = 0;
            break;
          case 1:
            handle->aac_config.ui_sbr_mode = 1;
            break;
          case 2:
            handle->aac_config.ui_sbr_mode = 1;
            break;
          case 3:
            handle->aac_config.ui_sbr_mode = 3;
            break;

          default:
            handle->aac_config.ui_sbr_mode = 0;
        }


        break;

      default:

        break;
    }
  }

  pstr_frame_data->scal_out_object_type =
      pstr_frame_data->str_audio_specific_config.audio_object_type;
  pstr_frame_data->scal_out_num_channels =
      pstr_frame_data->str_audio_specific_config.channel_configuration;
  pstr_frame_data->scal_out_sampling_frequency =
      pstr_frame_data->str_audio_specific_config.sampling_frequency;

  if (&(pstr_dec_data->str_usac_data) != NULL) {
    ia_sbr_header_data_struct usac_def_header;
    ia_audio_specific_config_struct *pstr_aud_spec_config =
        &pstr_frame_data->str_audio_specific_config;
    ia_usac_config_struct *ptr_usac_config =
        &(pstr_frame_data->str_audio_specific_config.str_usac_config);

    WORD32 inter_tes[MAX_NUM_ELEMENTS] = {0};
    WORD32 bs_pvc[MAX_NUM_ELEMENTS] = {0};
    WORD32 harmonic_sbr[MAX_NUM_ELEMENTS] = {0};
    WORD32 inter_test_flag = 0;
    WORD32 bs_pvc_flag = 0;
    WORD32 harmonic_Sbr_flag = 0;

    ia_usac_decoder_config_struct *ptr_usac_dec_config =
        &ptr_usac_config->str_usac_dec_config;
    WORD32 const num_ele = ptr_usac_dec_config->num_elements;
    WORD32 elem_idx = 0;

    memset(&usac_def_header, 0, sizeof(ia_sbr_header_data_struct));

    for (elem_idx = 0; elem_idx < num_ele; elem_idx++) {
      UWORD32 usac_ele_type =
          ptr_usac_config->str_usac_dec_config.usac_element_type[elem_idx];
      ia_usac_dec_element_config_struct *ptr_usac_ele_config =
          &ptr_usac_config->str_usac_dec_config
               .str_usac_element_config[elem_idx];

      ia_usac_dec_sbr_config_struct *ptr_usac_sbr_config =
          &(ptr_usac_dec_config->str_usac_element_config[elem_idx]
                .str_usac_sbr_config);
      inter_tes[elem_idx] =
          (ptr_usac_sbr_config != NULL) ? ptr_usac_sbr_config->bs_inter_tes : 0;
      bs_pvc[elem_idx] =
          (ptr_usac_sbr_config != NULL) ? ptr_usac_sbr_config->bs_pvc : 0;
      harmonic_sbr[elem_idx] =
          (ptr_usac_sbr_config != NULL) ? ptr_usac_sbr_config->harmonic_sbr : 0;

      if (ptr_usac_sbr_config->bs_inter_tes) inter_test_flag = 1;
      if (ptr_usac_sbr_config->bs_pvc) bs_pvc_flag = 1;
      if (ptr_usac_sbr_config->harmonic_sbr) harmonic_Sbr_flag = 1;

      if ((usac_ele_type != ID_USAC_LFE) && (usac_ele_type != ID_USAC_EXT)) {
        ia_usac_dec_sbr_config_struct *ptr_usac_sbr_config =
            &(ptr_usac_ele_config->str_usac_sbr_config);

        usac_def_header.start_freq = ptr_usac_sbr_config->dflt_start_freq;
        usac_def_header.stop_freq = ptr_usac_sbr_config->dflt_stop_freq;
        usac_def_header.header_extra_1 =
            ptr_usac_sbr_config->dflt_header_extra1;
        usac_def_header.header_extra_2 =
            ptr_usac_sbr_config->dflt_header_extra2;
        usac_def_header.freq_scale = ptr_usac_sbr_config->dflt_freq_scale;
        usac_def_header.alter_scale = ptr_usac_sbr_config->dflt_alter_scale;
        usac_def_header.noise_bands = ptr_usac_sbr_config->dflt_noise_bands;
        usac_def_header.limiter_bands = ptr_usac_sbr_config->dflt_limiter_bands;
        usac_def_header.limiter_gains = ptr_usac_sbr_config->dflt_limiter_gains;
        usac_def_header.interpol_freq = ptr_usac_sbr_config->dflt_interpol_freq;
        usac_def_header.smoothing_mode =
            ptr_usac_sbr_config->dflt_smoothing_mode;
      }
    }

    pstr_dec_data->str_usac_data.down_samp_sbr = 0;

    if (pstr_dec_data->str_usac_data.sbr_ratio_idx > 0) {
      if (pstr_aud_spec_config->ext_sampling_frequency ==
          pstr_aud_spec_config->sampling_frequency) {
        pstr_dec_data->str_usac_data.down_samp_sbr = 1;
      }
      if (pstr_dec_data->str_usac_data.down_samp_sbr == 0) {
        if (pstr_dec_data->str_usac_data.sbr_ratio_idx == 3) {
          pstr_frame_data->scal_out_sampling_frequency =
              4 * pstr_frame_data->scal_out_sampling_frequency;
        } else {
          pstr_frame_data->scal_out_sampling_frequency =
              2 * pstr_frame_data->scal_out_sampling_frequency;
        }
      }

      {
        void *sbr_persistent_mem_v = aac_dec_handle->sbr_persistent_mem_u;

        pstr_dec_data->str_usac_data.pstr_esbr_dec = ixheaacd_init_sbr(
            pstr_frame_data->str_layer.sample_rate_layer,
            pstr_dec_data->str_usac_data.ccfl,
            &pstr_dec_data->str_usac_data.down_samp_sbr, sbr_persistent_mem_v,
            NULL, pstr_frame_data->scal_out_num_channels, 0,
            pstr_dec_data->str_usac_data.sbr_ratio_idx,
            pstr_dec_data->str_usac_data.output_samples, &harmonic_Sbr_flag,
            (void *)&usac_def_header, aac_dec_handle->str_sbr_config,
            pstr_dec_data->str_usac_data.audio_object_type);
        pstr_dec_data->str_usac_data.sbr_scratch_mem_base =
            aac_dec_handle->sbr_scratch_mem_u;
        if (num_ele)
          ixheaacd_setesbr_flags(sbr_persistent_mem_v, bs_pvc_flag,
                                 harmonic_Sbr_flag, inter_test_flag);
      }

      if (pstr_dec_data->str_usac_data.pstr_esbr_dec == NULL) {
        return -1;
      } else {
        pstr_dec_data->str_usac_data.pstr_esbr_dec->xaac_jmp_buf =
            &(aac_dec_handle->xaac_jmp_buf);
      }
    }
  }
  aac_dec_handle->decode_create_done = 1;
  return 0;
}