/*************************************************************************** * * 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. * ****************************************************************************/ // Standard C Included Files #include "app_audio.h" #include "app_overlay.h" #include "app_ring_merge.h" #include "audio_prompt_sbc.h" #include "bt_sco_chain.h" #include "cmsis_os.h" #include "cqueue.h" #include "hal_timer.h" #include "hal_trace.h" #include "hal_uart.h" #include "hfp_api.h" #include "iir_resample.h" #include "plat_types.h" #include "tgt_hardware.h" #include #include #include #include #include #ifdef TX_RX_PCM_MASK #include "bt_drv_interface.h" #endif #define ENABLE_LPC_PLC #define ENABLE_PLC_ENCODER // BT #include "a2dp_api.h" #ifdef TX_RX_PCM_MASK #include "bt_drv_interface.h" #include "hal_chipid.h" #endif #include "plc_utils.h" extern "C" { #include "plc_8000.h" #include "speech_utils.h" #if defined(HFP_1_6_ENABLE) #include "codec_sbc.h" #if defined(ENABLE_LPC_PLC) #include "lpc_plc_api.h" #else #include "plc_16000.h" #endif #endif #if defined(CVSD_BYPASS) #include "Pcm8k_Cvsd.h" #endif #if defined(SPEECH_TX_24BIT) extern int32_t *aec_echo_buf; #else extern short *aec_echo_buf; #endif #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) static uint8_t *echo_buf_queue; static uint16_t echo_buf_q_size; static uint16_t echo_buf_q_wpos; static uint16_t echo_buf_q_rpos; static bool echo_buf_q_full; #endif #endif static void *speech_plc; } // #define PENDING_MSBC_DECODER_ALG // #define SPEECH_RX_PLC_DUMP_DATA #ifdef SPEECH_RX_PLC_DUMP_DATA #include "audio_dump.h" int16_t *audio_dump_temp_buf = NULL; #endif // app_bt_stream.cpp::bt_sco_player(), used buffer size #define APP_BT_STREAM_USE_BUF_SIZE (1024 * 2) #if defined(SCO_OPTIMIZE_FOR_RAM) uint8_t *sco_overlay_ram_buf = NULL; int sco_overlay_ram_buf_len = 0; #endif static bool resample_needed_flag = false; static int sco_frame_length; static int codec_frame_length; static int16_t *upsample_buf_for_msbc = NULL; static int16_t *downsample_buf_for_msbc = NULL; static IirResampleState *upsample_st = NULL; static IirResampleState *downsample_st = NULL; #define VOICEBTPCM_TRACE(s, ...) // TRACE(s, ##__VA_ARGS__) /* voicebtpcm_pcm queue */ #define FRAME_NUM (4) #define VOICEBTPCM_PCM_16k_FRAME_LENGTH \ (SPEECH_FRAME_MS_TO_LEN(16000, SPEECH_SCO_FRAME_MS)) #define VOICEBTPCM_PCM_16K_QUEUE_SIZE \ (VOICEBTPCM_PCM_16k_FRAME_LENGTH * FRAME_NUM) #define VOICEBTPCM_PCM_8k_FRAME_LENGTH \ (SPEECH_FRAME_MS_TO_LEN(8000, SPEECH_SCO_FRAME_MS)) #define VOICEBTPCM_PCM_8K_QUEUE_SIZE \ (VOICEBTPCM_PCM_8k_FRAME_LENGTH * FRAME_NUM) // #endif CQueue voicebtpcm_p2m_pcm_queue; CQueue voicebtpcm_m2p_pcm_queue; static int32_t voicebtpcm_p2m_cache_threshold; static int32_t voicebtpcm_m2p_cache_threshold; static int32_t voicebtpcm_p2m_pcm_cache_size; static int32_t voicebtpcm_m2p_pcm_cache_size; static enum APP_AUDIO_CACHE_T voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_QTY; static enum APP_AUDIO_CACHE_T voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_QTY; extern bool bt_sco_codec_is_msbc(void); #define ENCODE_TEMP_PCM_LEN (120) #define MSBC_FRAME_SIZE (60) #if defined(HFP_1_6_ENABLE) static btif_sbc_decoder_t msbc_decoder; static float msbc_eq_band_gain[CFG_HW_AUD_EQ_NUM_BANDS] = {0, 0, 0, 0, 0, 0, 0, 0}; #define MSBC_ENCODE_PCM_LEN (240) unsigned char *temp_msbc_buf; unsigned char *temp_msbc_buf1; #if defined(ENABLE_LPC_PLC) LpcPlcState *msbc_plc_state = NULL; #else struct PLC_State msbc_plc_state; #endif #ifdef ENABLE_PLC_ENCODER static btif_sbc_encoder_t *msbc_plc_encoder; static int16_t *msbc_plc_encoder_buffer = NULL; #define MSBC_CODEC_DELAY (73) static uint8_t enc_tmp_buf[MSBC_FRAME_SIZE - 3]; static uint8_t dec_tmp_buf[MSBC_ENCODE_PCM_LEN]; #endif // static sbc_encoder_t sbc_Encoder1; // static btif_sbc_pcm_data_t PcmEncData1; static btif_sbc_encoder_t *msbc_encoder; static btif_sbc_pcm_data_t msbc_encoder_pcmdata; static unsigned char msbc_counter = 0x08; #endif int decode_msbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len); int decode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len); // playback flow // bt-->store_voicebtpcm_m2p_buffer-->decode_voicebtpcm_m2p_frame-->audioflinger // playback-->speaker used by playback, store data from bt to memory int store_voicebtpcm_m2p_buffer(unsigned char *buf, unsigned int len) { // TRACE(2,"[%s]: %d", __FUNCTION__, // FAST_TICKS_TO_US(hal_fast_sys_timer_get())); int size; #if defined(HFP_1_6_ENABLE) if (bt_sco_codec_is_msbc()) { decode_msbc_frame(buf, len); } else #endif { #if defined(CVSD_BYPASS) decode_cvsd_frame(buf, len); #endif if (speech_plc) { speech_plc_8000((PlcSt_8000 *)speech_plc, (short *)buf, len); } LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)buf, len); UNLOCK_APP_AUDIO_QUEUE(); } size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_m2p_pcm_queue); if (size >= voicebtpcm_m2p_cache_threshold) { voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_OK; } // TRACE(2,"m2p :%d/%d", len, size); return 0; } #if defined(CVSD_BYPASS) #define VOICECVSD_TEMP_BUFFER_SIZE 120 #define VOICECVSD_ENC_SIZE 60 static short cvsd_decode_buff[VOICECVSD_TEMP_BUFFER_SIZE * 2]; int decode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len) { uint32_t r = 0, decode_len = 0; unsigned char *e1 = NULL, *e2 = NULL; unsigned int len1 = 0, len2 = 0; while (decode_len < pcm_len) { LOCK_APP_AUDIO_QUEUE(); len1 = len2 = 0; e1 = e2 = 0; r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue, VOICECVSD_TEMP_BUFFER_SIZE, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); if (r == CQ_ERR) { memset(pcm_buffer, 0, pcm_len); TRACE(0, "cvsd spk buff underflow"); return 0; } if (len1 != 0) { CvsdToPcm8k(e1, (short *)(cvsd_decode_buff), len1, 0); LOCK_APP_AUDIO_QUEUE(); DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, len1); UNLOCK_APP_AUDIO_QUEUE(); decode_len += len1 * 2; } if (len2 != 0) { CvsdToPcm8k(e2, (short *)(cvsd_decode_buff), len2, 0); LOCK_APP_AUDIO_QUEUE(); DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, len2); UNLOCK_APP_AUDIO_QUEUE(); decode_len += len2 * 2; } } memcpy(pcm_buffer, cvsd_decode_buff, decode_len); return decode_len; } int encode_cvsd_frame(unsigned char *pcm_buffer, unsigned int pcm_len) { uint32_t r = 0; unsigned char *e1 = NULL, *e2 = NULL; unsigned int len1 = 0, len2 = 0; uint32_t processed_len = 0; uint32_t remain_len = 0, enc_len = 0; while (processed_len < pcm_len) { remain_len = pcm_len - processed_len; if (remain_len >= (VOICECVSD_ENC_SIZE * 2)) { enc_len = VOICECVSD_ENC_SIZE * 2; } else { enc_len = remain_len; } LOCK_APP_AUDIO_QUEUE(); len1 = len2 = 0; e1 = e2 = 0; r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, enc_len, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); if (r == CQ_ERR) { memset(pcm_buffer, 0x55, pcm_len); TRACE(0, "cvsd spk buff underflow"); return 0; } if (e1) { Pcm8kToCvsd((short *)e1, (unsigned char *)(pcm_buffer + processed_len), len1 / 2); LOCK_APP_AUDIO_QUEUE(); DeCQueue(&voicebtpcm_p2m_pcm_queue, NULL, len1); UNLOCK_APP_AUDIO_QUEUE(); processed_len += len1; } if (e2) { Pcm8kToCvsd((short *)e2, (unsigned char *)(pcm_buffer + processed_len), len2 / 2); LOCK_APP_AUDIO_QUEUE(); DeCQueue(&voicebtpcm_p2m_pcm_queue, NULL, len2); UNLOCK_APP_AUDIO_QUEUE(); processed_len += len2; } } #if 0 for (int cc = 0; cc < 32; ++cc) { TRACE(1,"%x-", e1[cc]); } #endif TRACE(3, "%s: processed_len %d, pcm_len %d", __func__, processed_len, pcm_len); return processed_len; } #endif #if defined(HFP_1_6_ENABLE) inline int sco_parse_synchronization_header(uint8_t *buf, uint8_t *sn) { uint8_t sn1, sn2; *sn = 0xff; if ((buf[0] != 0x01) || ((buf[1] & 0x0f) != 0x08) || (buf[2] != 0xad)) { return -1; } sn1 = (buf[1] & 0x30) >> 4; sn2 = (buf[1] & 0xc0) >> 6; if ((sn1 != 0) && (sn1 != 0x3)) { return -2; } if ((sn2 != 0) && (sn2 != 0x3)) { return -3; } *sn = (sn1 & 0x01) | (sn2 & 0x02); return 0; } #if 1 #define MSBC_LEN_FORMBT_PER_FRAME (120) // Bytes; only for BES platform. #define SAMPLES_LEN_PER_FRAME (120) #define MSBC_LEN_PER_FRAME (57 + 3) #if defined(CHIP_BEST1400) || defined(CHIP_BEST1402) || \ defined(CHIP_BEST2300P) || defined(CHIP_BEST2300A) || \ defined(CHIP_BEST2001) #define MSBC_MUTE_PATTERN (0x5555) #else #define MSBC_MUTE_PATTERN (0x0000) #endif #if !defined(PENDING_MSBC_DECODER_ALG) short DecPcmBuf[SAMPLES_LEN_PER_FRAME]; unsigned char DecMsbcBuf[MSBC_LEN_PER_FRAME]; unsigned short DecMsbcBufAll[MSBC_LEN_FORMBT_PER_FRAME * 5]; unsigned int next_frame_flag = 0; static int msbc_find_first_sync = 0; static unsigned int msbc_offset = 0; static PacketLossState pld; int decode_msbc_frame(unsigned char *msbc_btpcm_buffer, unsigned int msbc_len) { btif_sbc_pcm_data_t pcm_data; unsigned int msbc_offset_lowdelay = 0; unsigned int i, j; unsigned short *msbc_buffer = (unsigned short *)msbc_btpcm_buffer; int frame_flag[6]; // 1: good frame; 0:bad frame; bt_status_t ret; unsigned int frame_counter = 0; unsigned short byte_decode = 0; unsigned int msbc_offset_total = 0; int msbc_offset_drift[6] = { 0, }; // unsigned int timer_begin=hal_sys_timer_get(); // TRACE(1,"decode_msbc_frame,msbc_len:%d",msbc_len); #ifdef TX_RX_PCM_MASK if (btdrv_is_pcm_mask_enable() == 1) { memcpy((uint8_t *)DecMsbcBufAll, msbc_buffer, msbc_len); } else #endif { for (i = 0; i < msbc_len / 2; i++) { DecMsbcBufAll[i + (MSBC_LEN_FORMBT_PER_FRAME / 2)] = msbc_buffer[i]; } } /* for(i =0; i= msbc_offset_total) frame_flag[j] = 3; else frame_flag[j] = 1; } } } } #ifdef TX_RX_PCM_MASK if (btdrv_is_pcm_mask_enable() == 0) #endif { for (j = 0; j < msbc_len / MSBC_LEN_FORMBT_PER_FRAME; j++) { value = value | frame_flag[j]; } // abnormal msbc packet. if (value > 1) msbc_find_first_sync = 0; } } while (frame_counter < msbc_len / MSBC_LEN_FORMBT_PER_FRAME) { // TRACE(3,"[%s] decoding, offset %d, offset drift %d", __FUNCTION__, // msbc_offset, msbc_offset_drift[frame_counter]); // skip first byte when msbc_offset == 0 and msbc_offset_drift == -1 unsigned int start_idx = 0; if (msbc_offset_lowdelay == 0 && msbc_offset_drift[frame_counter] == -1) { start_idx = 1; DecMsbcBuf[0] = 0x01; } for (i = start_idx; i < MSBC_LEN_PER_FRAME; i++) { // DecMsbcBuf[i]=DecMsbcBufAll[i+msbc_offset_lowdelay+frame_counter*(MSBC_LEN_FORMBT_PER_FRAME/2)+2]>>8; DecMsbcBuf[i] = DecMsbcBufAll[i + msbc_offset_lowdelay + msbc_offset_drift[frame_counter] + frame_counter * (MSBC_LEN_FORMBT_PER_FRAME / 2)] >> 8; } // TRACE(1,"msbc header:0x%x",DecMsbcBuf[0]); #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_add_channel_data(2, (short *)DecMsbcBuf, MSBC_LEN_PER_FRAME / 2); #endif plc_type_t plc_type = packet_loss_detection_process(&pld, DecMsbcBuf); if (plc_type != PLC_TYPE_PASS) { memset(DecPcmBuf, 0, sizeof(DecPcmBuf)); goto do_plc; } pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; pcm_data.numChannels = 1; pcm_data.dataLen = 0; pcm_data.data = (uint8_t *)DecPcmBuf; ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)DecMsbcBuf, MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data, SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain); // ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail", // __FUNCTION__); if (ret != BT_STS_SUCCESS) { plc_type = PLC_TYPE_DECODER_ERROR; packet_loss_detection_update_histogram(&pld, plc_type); } do_plc: if (plc_type == PLC_TYPE_PASS) { #if defined(ENABLE_LPC_PLC) lpc_plc_save(msbc_plc_state, DecPcmBuf); #else PLC_good_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf); #endif #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_add_channel_data(0, (short *)DecPcmBuf, MSBC_ENCODE_PCM_LEN / 2); #endif } else { TRACE(1, "PLC bad frame, plc_type: %d", plc_type); #if defined(PLC_DEBUG_PRINT_DATA) DUMP8("0x%02x, ", DecMsbcBuf, 60); #endif #ifdef SPEECH_RX_PLC_DUMP_DATA for (uint32_t i = 0; i < MSBC_ENCODE_PCM_LEN / 2; i++) { audio_dump_temp_buf[i] = (plc_type - 1) * 5000; } audio_dump_add_channel_data(0, audio_dump_temp_buf, MSBC_ENCODE_PCM_LEN / 2); #endif #if defined(ENABLE_LPC_PLC) lpc_plc_generate(msbc_plc_state, DecPcmBuf, #if defined(ENABLE_PLC_ENCODER) msbc_plc_encoder_buffer #else NULL #endif ); #if defined(ENABLE_PLC_ENCODER) pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; pcm_data.numChannels = 1; pcm_data.dataLen = MSBC_ENCODE_PCM_LEN; pcm_data.data = (uint8_t *)(msbc_plc_encoder_buffer + MSBC_CODEC_DELAY); uint16_t encoded_bytes = 0, buf_len = MSBC_FRAME_SIZE - 3; ret = btif_sbc_encode_frames(msbc_plc_encoder, &pcm_data, &encoded_bytes, enc_tmp_buf, &buf_len, 0xFFFF); ASSERT(ret == BT_STS_SUCCESS, "[%s] plc encoder must success", __FUNCTION__); ASSERT(encoded_bytes == MSBC_ENCODE_PCM_LEN, "[%s] plc encoder encoded bytes error", __FUNCTION__); ASSERT(buf_len == MSBC_FRAME_SIZE - 3, "[%s] plc encoder encoded stream length error", __FUNCTION__); pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; pcm_data.numChannels = 1; pcm_data.dataLen = 0; pcm_data.data = dec_tmp_buf; ret = btif_sbc_decode_frames(&msbc_decoder, enc_tmp_buf, MSBC_FRAME_SIZE - 3, &byte_decode, &pcm_data, MSBC_ENCODE_PCM_LEN, msbc_eq_band_gain); ASSERT(ret == BT_STS_SUCCESS, "[%s] plc decoder must success", __FUNCTION__); ASSERT(byte_decode == MSBC_FRAME_SIZE - 3, "[%s] plc decoder decoded bytes error", __FUNCTION__); #endif #else pcm_data.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; pcm_data.numChannels = 1; pcm_data.dataLen = 0; pcm_data.data = (uint8_t *)DecPcmBuf; ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)indices0, MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data, SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain); PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf); ASSERT(ret == BT_STS_SUCCESS, "[%s] msbc decoder should never fail", __FUNCTION__); #endif } #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_add_channel_data(1, (short *)DecPcmBuf, MSBC_ENCODE_PCM_LEN / 2); audio_dump_run(); #endif LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)DecPcmBuf, (unsigned int)(SAMPLES_LEN_PER_FRAME * 2)); UNLOCK_APP_AUDIO_QUEUE(); frame_counter++; } #ifdef TX_RX_PCM_MASK if (btdrv_is_pcm_mask_enable() == 0) #endif { for (i = 0; i < MSBC_LEN_FORMBT_PER_FRAME / 2; i++) { DecMsbcBufAll[i] = DecMsbcBufAll[i + (msbc_len / 2)]; } } // TRACE(1,"msbc + plc:%d", (hal_sys_timer_get()-timer_begin)); return 0; } #else static uint8_t *msbc_buf_before_decode; short DecPcmBuf[SAMPLES_LEN_PER_FRAME]; unsigned char DecMsbcBuf[MSBC_LEN_PER_FRAME]; unsigned short DecMsbcBufAll[MSBC_LEN_FORMBT_PER_FRAME * 5]; unsigned char DecVerifyMsbcBuf[MSBC_LEN_PER_FRAME * 2]; unsigned int next_frame_flag = 0; uint8_t last_msbc_sync_num = 0; CQueue msbc_temp_queue; __attribute__((section(".fast_text_sram"))) int decode_msbc_frame(unsigned char *msbc_btpcm_buffer, unsigned int msbc_len) { btif_sbc_pcm_data_t pcm_data; uint16_t msbc_queue_len = 0, msbc_sync_offset = 0; unsigned char *e1 = NULL, *e2 = NULL; unsigned int len1 = 0, len2 = 0; int r = 0; uint8_t sync_num = 0, verify_result = 0; uint8_t frame_decode_num = 0; int plc_num = 0; bt_status_t ret; unsigned short byte_decode = 0; pcm_data.data = (unsigned char *)DecPcmBuf; pcm_data.dataLen = 0; // put msbc in queue for (int j = 0; j < (int)msbc_len; j += MSBC_LEN_PER_FRAME * 2) { for (int i = 0; i < MSBC_LEN_PER_FRAME; i++) { DecMsbcBuf[i] = msbc_btpcm_buffer[2 * i + 1 + j]; } APP_AUDIO_EnCQueue(&msbc_temp_queue, DecMsbcBuf, MSBC_LEN_PER_FRAME); } msbc_find_sync_again: msbc_queue_len = APP_AUDIO_LengthOfCQueue(&msbc_temp_queue); TRACE(1, "length = %d", msbc_queue_len); if (msbc_queue_len > MSBC_LEN_PER_FRAME * 2) msbc_queue_len = MSBC_LEN_PER_FRAME * 2; else if (msbc_queue_len < MSBC_LEN_PER_FRAME) return 0; r = APP_AUDIO_PeekCQueue(&msbc_temp_queue, msbc_queue_len, &e1, &len1, &e2, &len2); if (r == CQ_OK) { if (len1) { memcpy(DecVerifyMsbcBuf, e1, len1); } if (len2 != 0) { memcpy(DecVerifyMsbcBuf + len1, e2, len2); } } else { // can't happen } // DUMP8("%02x", DecVerifyMsbcBuf, msbc_queue_len); // find sync head for (int i = 0; i < (msbc_queue_len - 3); i++) { // verify sync success if (sco_parse_synchronization_header(DecVerifyMsbcBuf + i, &sync_num) >= 0) { verify_result = 1; msbc_sync_offset = i; break; } } TRACE(3, "%02x %02x %02x", (DecVerifyMsbcBuf + msbc_sync_offset)[0], (DecVerifyMsbcBuf + msbc_sync_offset)[1], (DecVerifyMsbcBuf + msbc_sync_offset)[2]); TRACE(5, "msbc:%d %d %d %d %d\n", verify_result, msbc_queue_len, msbc_sync_offset, last_msbc_sync_num, sync_num); if (!verify_result) { // remove msbc frame remain 3 byted as it may include syn head APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, msbc_queue_len - 3); goto msbc_find_sync_again; } else { // remove invalid msbc frame space APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, msbc_sync_offset); if (msbc_sync_offset >= MSBC_LEN_PER_FRAME) goto msbc_find_sync_again; } // cal plc number if ((last_msbc_sync_num + 1) % 4 == sync_num) { plc_num = 0; } else { for (int i = 0; i < 4; i++) { if ((last_msbc_sync_num + i) % 4 == sync_num) { break; } plc_num++; } } last_msbc_sync_num = sync_num; // failed check sync should do plc if (plc_num > 0) { for (int i = 0; i < plc_num; i++) { ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)indices0, MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data, SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain); if (ret == BT_STS_SUCCESS) { TRACE(1, "PLC bad frame:%d\n", ret); // timer_begin=hal_sys_timer_get(); PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf); // TRACE(1,"msbc + plc:%d", (hal_sys_timer_get()-timer_begin)); pcm_data.data = (unsigned char *)DecPcmBuf; pcm_data.dataLen = 0; LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)DecPcmBuf, (unsigned int)(SAMPLES_LEN_PER_FRAME * 2)); UNLOCK_APP_AUDIO_QUEUE(); } else { ASSERT(0, "ERROR inices0", __func__); } } } { ret = btif_sbc_decode_frames( &msbc_decoder, (unsigned char *)DecVerifyMsbcBuf + msbc_sync_offset + 2, MSBC_LEN_PER_FRAME, &byte_decode, &pcm_data, SAMPLES_LEN_PER_FRAME * 2, msbc_eq_band_gain); if (ret == BT_STS_SUCCESS) { PLC_good_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf); pcm_data.data = (unsigned char *)DecPcmBuf; pcm_data.dataLen = 0; } else { TRACE(1, "PLC bad frame:%d\n"); PLC_bad_frame(&msbc_plc_state, DecPcmBuf, DecPcmBuf); pcm_data.data = (unsigned char *)DecPcmBuf; pcm_data.dataLen = 0; TRACE(1, "ERROR msbc frame!ret:%d\n", ret); } // remove msbc frame APP_AUDIO_DeCQueue(&msbc_temp_queue, 0, MSBC_LEN_PER_FRAME); LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_EnCQueue(&voicebtpcm_m2p_pcm_queue, (unsigned char *)DecPcmBuf, (unsigned int)(SAMPLES_LEN_PER_FRAME * 2)); UNLOCK_APP_AUDIO_QUEUE(); frame_decode_num++; if (frame_decode_num <= (msbc_len / (MSBC_LEN_PER_FRAME * 2) - 1)) goto msbc_find_sync_again; } return 0; } #endif // #if !defined(PENDING_MSBC_DECODER_ALG) #else int decode_msbc_frame(unsigned char *pcm_buffer, unsigned int pcm_len) { int ttt = 0; // int t = 0; uint8_t underflow = 0; #if defined(MSBC_PLC_ENABLE) uint8_t plc_type = 0; uint8_t need_check_pkt = 1; uint8_t msbc_raw_sn = 0xff; static uint8_t msbc_raw_sn_pre; static uint8_t msbc_raw_sn_pre2; static bool msbc_find_first_sync = 0; #endif int r = 0; unsigned char *e1 = NULL, *e2 = NULL, *msbc_buff = NULL; unsigned int len1 = 0, len2 = 0; static btif_sbc_pcm_data_t pcm_data; static unsigned int msbc_next_frame_size; bt_status_t ret = BT_STS_SUCCESS; unsigned short byte_decode = 0; unsigned int pcm_offset = 0; unsigned int pcm_processed = 0; #if defined(MSBC_PLC_ENABLE) pcm_data.data = (unsigned char *)msbc_buf_before_plc; #else pcm_data.data = (unsigned char *)pcm_buffer; #endif if (!msbc_next_frame_size) { msbc_next_frame_size = MSBC_FRAME_SIZE; } // reinit: if (need_init_decoder) { TRACE(0, "init msbc decoder\n"); pcm_data.data = (unsigned char *)(pcm_buffer + pcm_offset); pcm_data.dataLen = 0; btif_sbc_init_decoder(&msbc_decoder); msbc_decoder.streamInfo.mSbcFlag = 1; msbc_decoder.streamInfo.bitPool = 26; msbc_decoder.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; msbc_decoder.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO; msbc_decoder.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS; /* Number of blocks used to encode the stream (4, 8, 12, or 16) */ msbc_decoder.streamInfo.numBlocks = BTIF_MSBC_BLOCKS; /* The number of subbands in the stream (4 or 8) */ msbc_decoder.streamInfo.numSubBands = 8; msbc_decoder.streamInfo.numChannels = 1; #if defined(MSBC_PLC_ENCODER) btif_sbc_init_encoder(&sbc_Encoder1); sbc_Encoder1.streamInfo.mSbcFlag = 1; sbc_Encoder1.streamInfo.numChannels = 1; sbc_Encoder1.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO; sbc_Encoder1.streamInfo.bitPool = 26; sbc_Encoder1.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; sbc_Encoder1.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS; sbc_Encoder1.streamInfo.numBlocks = BTIF_MSBC_BLOCKS; sbc_Encoder1.streamInfo.numSubBands = 8; #endif #if defined(MSBC_PLC_ENABLE) InitPLC(&msbc_plc_state); msbc_need_check_sync_header = 0; msbc_raw_sn_pre = 0xff; msbc_raw_sn_pre2 = 0xff; msbc_find_first_sync = true; #endif } #if defined(MSBC_PLC_ENABLE) need_check_pkt = 1; #endif msbc_buff = msbc_buf_before_decode; get_again: LOCK_APP_AUDIO_QUEUE(); len1 = len2 = 0; e1 = e2 = 0; r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue, msbc_next_frame_size, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); if (r == CQ_ERR) { pcm_processed = pcm_len; memset(pcm_buffer, 0, pcm_len); TRACE(0, "msbc spk buff underflow"); goto exit; } if (!len1) { TRACE(2, "len1 underflow %d/%d\n", len1, len2); goto get_again; } if (len1 > 0 && e1) { memcpy(msbc_buff, e1, len1); } if (len2 > 0 && e2) { memcpy(msbc_buff + len1, e2, len2); } if (msbc_find_first_sync) { for (uint8_t i = 0; i < MSBC_FRAME_SIZE - 3; i++) { if (!sco_parse_synchronization_header(&msbc_buff[i], &msbc_raw_sn)) { TRACE(2, "1 msbc find sync sn:%d offset:%d", msbc_raw_sn, i); msbc_find_first_sync = false; goto start_decoder; } } LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, MSBC_FRAME_SIZE - 3); UNLOCK_APP_AUDIO_QUEUE(); memset(pcm_buffer, 0, pcm_len); pcm_processed = pcm_len; goto exit; } start_decoder: // DUMP8("%02x ", msbc_buf_before_decode, 8); #if defined(MSBC_PLC_ENABLE) // [0]-1,msbc sync byte // [1]-seqno // code_frame(57 bytes) // padding(1 byte) if (need_check_pkt) { #if 1 if (!sco_parse_synchronization_header(msbc_buf_before_decode, &msbc_raw_sn)) { if (msbc_raw_sn_pre2 == 0xff) { // do nothing msbc_raw_sn_pre2 = msbc_raw_sn; } else { if (((msbc_raw_sn_pre2 + 1) % 4) == msbc_raw_sn) { // do nothing msbc_raw_sn_pre2 = msbc_raw_sn; } else if (msbc_raw_sn == 0xff) { TRACE(1, "xxxxxx: sbchd err:%d", MSBC_FRAME_SIZE - 3); } else { TRACE(2, "xxxxxx: seq err:%d/%d", msbc_raw_sn, msbc_raw_sn_pre2); msbc_raw_sn_pre2 = (msbc_raw_sn_pre2 + 1) % 4; #if 1 memset(msbc_buf_before_decode, 0, MSBC_FRAME_SIZE); #else if (msbc_raw_sn_pre2 == 0) { msbc_buf_before_decode[1] = 0x08; } else if (msbc_raw_sn_pre2 == 1) { msbc_buf_before_decode[1] = 0x38; } else if (msbc_raw_sn_pre2 == 2) { msbc_buf_before_decode[1] = 0xc8; } else if (msbc_raw_sn_pre2 == 3) { msbc_buf_before_decode[1] = 0xf8; } else { ASSERT(0, "msbc_raw_sn_pre2(%d) error", __func__); } #endif } } } #endif unsigned int sync_offset = 0; if (msbc_need_check_sync_header) { do { if (!sco_parse_synchronization_header(&msbc_buff[sync_offset], &msbc_raw_sn)) { break; } sync_offset++; } while (sync_offset < (MSBC_FRAME_SIZE - 3)); msbc_need_check_sync_header = 0; if (sync_offset > 0 && sync_offset != (MSBC_FRAME_SIZE - 3)) { LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, sync_offset); UNLOCK_APP_AUDIO_QUEUE(); TRACE(1, "fix sync:%d", sync_offset); msbc_raw_sn_pre = (msbc_raw_sn + 3) % 4; // Find pre sn msbc_raw_sn_pre2 = msbc_raw_sn_pre; goto get_again; // TRACE(4,"***msbc_need_check_sync %d :%x %x %x\n", sync_offset, // msbc_buf_before_decode[0], // msbc_buf_before_decode[1], // msbc_buf_before_decode[2]); } else if (sync_offset == (MSBC_FRAME_SIZE - 3)) { // APP_AUDIO_DeCQueue(&voicebtpcm_m2p_queue, 0, sync_offset); // just jump sync length + padding length(1byte) // will in plc again, so can check sync again // TRACE(4,"***msbc_need_check_sync %d :%x %x %x\n", sync_offset, // msbc_buf_before_decode[0], // msbc_buf_before_decode[1], // msbc_buf_before_decode[2]); msbc_next_frame_size = (MSBC_FRAME_SIZE - 3) - 1; } else if (!sync_offset) { } else { TRACE(1, "3 msbc_need_check_sync %d\n", sync_offset); } } // 0 - normal decode without plc proc, 1 - normal decode with plc proc, 2 - // special decode with plc proc plc_type = 0; if (msbc_can_plc) { if (sco_parse_synchronization_header(msbc_buf_before_decode, &msbc_raw_sn)) { plc_type = 2; msbc_need_check_sync_header = 1; } else { plc_type = 1; } } else { plc_type = 0; } if (msbc_raw_sn_pre == 0xff) { // do nothing msbc_raw_sn_pre = msbc_raw_sn; } else { if (((msbc_raw_sn_pre + 1) % 4) == msbc_raw_sn) { // do nothing msbc_raw_sn_pre = msbc_raw_sn; } else if (msbc_raw_sn == 0xff) { TRACE(1, "sbchd err:%d", MSBC_FRAME_SIZE - 3); msbc_need_check_sync_header = 1; LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, MSBC_FRAME_SIZE - 3); UNLOCK_APP_AUDIO_QUEUE(); msbc_raw_sn_pre = (msbc_raw_sn_pre + 1) % 4; plc_type = 2; } else { TRACE(2, "seq err:%d/%d", msbc_raw_sn, msbc_raw_sn_pre); msbc_need_check_sync_header = 1; plc_type = 2; msbc_raw_sn_pre = (msbc_raw_sn_pre + 1) % 4; } } need_check_pkt = 0; } // TRACE(3,"type %d, seqno 0x%x, q_space %d\n", plc_type, cur_pkt_seqno, // APP_AUDIO_AvailableOfCQueue(&voicebtpcm_m2p_queue)); #endif // DUMP8("%02x ", msbc_buf_before_decode, msbc_next_frame_size); // TRACE(0,"\n"); #if defined(MSBC_PLC_ENABLE) if (plc_type == 1) { ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)msbc_buf_before_decode, msbc_next_frame_size, &byte_decode, &pcm_data, pcm_len - pcm_offset, msbc_eq_band_gain); ttt = hal_sys_timer_get(); #if defined(MSBC_PCM_PLC_ENABLE) speech_plc_16000_AddToHistory((PlcSt_16000 *)speech_plc, (short *)pcm_data.data, pcm_len / 2); memcpy(pcm_buffer, pcm_data.data, pcm_len); #else PLC_good_frame(&msbc_plc_state, (short *)pcm_data.data, (short *)pcm_buffer); #endif #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_add_channel_data(0, (short *)pcm_buffer, pcm_len / 2); #endif } else if (plc_type == 2) { #if defined(MSBC_PCM_PLC_ENABLE) ret = BT_STS_SUCCESS; ttt = hal_sys_timer_get(); #if defined(MSBC_PLC_ENCODER) speech_plc_16000_Dofe((PlcSt_16000 *)speech_plc, (short *)pcm_buffer, EncInBuf, pcm_len / 2); #else speech_plc_16000_Dofe((PlcSt_16000 *)speech_plc, (short *)pcm_buffer, NULL, pcm_len / 2); #endif #else PLC_bad_frame(&msbc_plc_state, (short *)pcm_data.data, (short *)pcm_buffer); #endif #if defined(MSBC_PLC_ENCODER) { uint16_t bytes_encoded = 0, buf_len = MSBC_ENCODE_PCM_LEN; PcmEncData1.data = (uint8_t *)(EncInBuf + MSBC_ENC_BUFFER_OFFSET); PcmEncData1.dataLen = pcm_len; PcmEncData1.numChannels = 1; PcmEncData1.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; btif_sbc_encode_frames(&sbc_Encoder1, &PcmEncData1, &bytes_encoded, Encodedbuf1, &buf_len, 0xFFFF); #ifdef __SBC_FUNC_IN_ROM__ ret = SBC_ROM_FUNC.sbc_frames_decode( &msbc_decoder, Encodedbuf1, MSBC_FRAME_SIZE - 3, &byte_decode, &pcm_data, pcm_len - pcm_offset, msbc_eq_band_gain); #else ret = btif_sbc_decode_frames(&msbc_decoder, Encodedbuf1, MSBC_FRAME_SIZE - 3, &byte_decode, &pcm_data, pcm_len - pcm_offset, msbc_eq_band_gain); #endif } #endif TRACE(2, "b t:%d ret:%d\n", (hal_sys_timer_get() - ttt), ret); #ifdef SPEECH_RX_PLC_DUMP_DATA for (uint32_t i = 0; i < pcm_len / 2; i++) { audio_dump_temp_buf[i] = 32767; } audio_dump_add_channel_data(0, audio_dump_temp_buf, pcm_len / 2); #endif } else #endif { ret = btif_sbc_decode_frames(&msbc_decoder, (unsigned char *)msbc_buf_before_decode, msbc_next_frame_size, &byte_decode, &pcm_data, pcm_len - pcm_offset, msbc_eq_band_gain); #if defined(MSBC_PCM_PLC_ENABLE) speech_plc_16000_AddToHistory((PlcSt_16000 *)speech_plc, (short *)pcm_data.data, pcm_len / 2); memcpy(pcm_buffer, pcm_data.data, pcm_len); #endif #ifdef SPEECH_RX_PLC_DUMP_DATA for (uint32_t i = 0; i < pcm_len / 2; i++) { audio_dump_temp_buf[i] = -32767; } audio_dump_add_channel_data(0, audio_dump_temp_buf, pcm_len / 2); #endif } #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_add_channel_data(1, (short *)pcm_buffer, pcm_len / 2); audio_dump_run(); #endif #if 0 TRACE(1,"[0] %x", msbc_buf_before_decode[0]); TRACE(1,"[1] %x", msbc_buf_before_decode[1]); TRACE(1,"[2] %x", msbc_buf_before_decode[2]); TRACE(1,"[3] %x", msbc_buf_before_decode[3]); TRACE(1,"[4] %x", msbc_buf_before_decode[4]); #endif // TRACE(2,"sbcd ret %d %d\n", ret, byte_decode); if (ret == BT_STS_CONTINUE) { need_init_decoder = false; LOCK_APP_AUDIO_QUEUE(); VOICEBTPCM_TRACE(2, "000000 byte_decode =%d, current_len1 =%d", byte_decode, msbc_next_frame_size); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode); UNLOCK_APP_AUDIO_QUEUE(); msbc_next_frame_size = (MSBC_FRAME_SIZE - byte_decode) > 0 ? (MSBC_FRAME_SIZE - byte_decode) : MSBC_FRAME_SIZE; goto get_again; } else if (ret == BT_STS_SUCCESS) { need_init_decoder = false; pcm_processed = pcm_data.dataLen; pcm_data.dataLen = 0; LOCK_APP_AUDIO_QUEUE(); #if defined(MSBC_PLC_ENABLE) if (plc_type == 0) { byte_decode += 1; // padding APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode); } else { #if defined(MSBC_PCM_PLC_ENABLE) if (plc_type == 2) { pcm_processed = pcm_len; } else { if (msbc_next_frame_size < MSBC_FRAME_SIZE) msbc_next_frame_size += 1; // padding APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size); } #else if (msbc_next_frame_size < MSBC_FRAME_SIZE) msbc_next_frame_size += 1; // padding APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size); #endif } #else if (msbc_next_frame_size < MSBC_FRAME_SIZE) msbc_next_frame_size += 1; // padding APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, msbc_next_frame_size); #endif UNLOCK_APP_AUDIO_QUEUE(); msbc_next_frame_size = MSBC_FRAME_SIZE; #if defined(MSBC_PLC_ENABLE) // plc after a good frame if (!msbc_can_plc) { msbc_can_plc = true; } #endif } else if (ret == BT_STS_FAILED) { need_init_decoder = true; pcm_processed = pcm_len; pcm_data.dataLen = 0; memset(pcm_buffer, 0, pcm_len); TRACE(1, "err mutelen:%d\n", pcm_processed); LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode); UNLOCK_APP_AUDIO_QUEUE(); msbc_next_frame_size = MSBC_FRAME_SIZE; /* leave */ } else if (ret == BT_STS_NO_RESOURCES) { need_init_decoder = true; pcm_processed = pcm_len; pcm_data.dataLen = 0; memset(pcm_buffer, 0, pcm_len); TRACE(1, "no_res mutelen:%d\n", pcm_processed); LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, byte_decode); UNLOCK_APP_AUDIO_QUEUE(); msbc_next_frame_size = MSBC_FRAME_SIZE; } exit: if (underflow || need_init_decoder) { TRACE(2, "media_msbc_decoder underflow len:%d,need_init_decoder=%d\n ", pcm_len, need_init_decoder); } // TRACE(1,"pcm_processed %d", pcm_processed); return pcm_processed; } #endif #endif // capture flow // mic-->audioflinger // capture-->store_voicebtpcm_p2m_buffer-->get_voicebtpcm_p2m_frame-->bt used by // capture, store data from mic to memory int store_voicebtpcm_p2m_buffer(unsigned char *buf, unsigned int len) { int POSSIBLY_UNUSED size; unsigned int avail_size = 0; LOCK_APP_AUDIO_QUEUE(); // merge_two_trace_to_one_track_16bits(0, (uint16_t *)buf, (uint16_t *)buf, // len>>1); r = APP_AUDIO_EnCQueue(&voicebtpcm_p2m_queue, buf, len>>1); avail_size = APP_AUDIO_AvailableOfCQueue(&voicebtpcm_p2m_pcm_queue); if (len <= avail_size) { APP_AUDIO_EnCQueue(&voicebtpcm_p2m_pcm_queue, buf, len); } else { VOICEBTPCM_TRACE(2, "mic buff overflow %d/%d", len, avail_size); APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len - avail_size); APP_AUDIO_EnCQueue(&voicebtpcm_p2m_pcm_queue, buf, len); } size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_pcm_queue); UNLOCK_APP_AUDIO_QUEUE(); VOICEBTPCM_TRACE(2, "p2m :%d/%d", len, size); return 0; } #if defined(HFP_1_6_ENABLE) unsigned char get_msbc_counter(void) { if (msbc_counter == 0x08) { msbc_counter = 0x38; } else if (msbc_counter == 0x38) { msbc_counter = 0xC8; } else if (msbc_counter == 0xC8) { msbc_counter = 0xF8; } else if (msbc_counter == 0xF8) { msbc_counter = 0x08; } return msbc_counter; } #endif #if defined(TX_RX_PCM_MASK) CQueue Tx_esco_queue; CQueue Rx_esco_queue; CQueue *get_tx_esco_queue_ptr() { return &Tx_esco_queue; } CQueue *get_rx_esco_queue_ptr() { return &Rx_esco_queue; } #endif // used by capture, get the memory data which has be stored by // store_voicebtpcm_p2m_buffer() int get_voicebtpcm_p2m_frame(unsigned char *buf, unsigned int len) { int got_len = 0; // TRACE(2,"[%s] pcm_len = %d", __func__, len / 2); if (voicebtpcm_cache_p2m_status == APP_AUDIO_CACHE_CACHEING) { app_audio_memset_16bit((short *)buf, 0, len / 2); TRACE(1, "[%s] APP_AUDIO_CACHE_CACHEING", __func__); return len; } int msbc_encode_temp_len = MSBC_FRAME_SIZE * 2; ASSERT(len % msbc_encode_temp_len == 0, "[%s] len(%d) is invalid", __func__, len); int loop_cnt = len / msbc_encode_temp_len; len = msbc_encode_temp_len; for (int cnt = 0; cnt < loop_cnt; cnt++) { if (bt_sco_codec_is_msbc()) { #ifdef HFP_1_6_ENABLE uint16_t bytes_encoded = 0, buf_len = len; uint16_t *dest_buf = 0, offset = 0; int r = 0; unsigned char *e1 = NULL, *e2 = NULL; unsigned int len1 = 0, len2 = 0; got_len = 0; dest_buf = (uint16_t *)buf; LOCK_APP_AUDIO_QUEUE(); r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, MSBC_ENCODE_PCM_LEN, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); if (r == CQ_OK) { if (len1) { memcpy(temp_msbc_buf, e1, len1); LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len1); UNLOCK_APP_AUDIO_QUEUE(); got_len += len1; } if (len2 != 0) { memcpy(temp_msbc_buf + got_len, e2, len2); got_len += len2; LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len2); UNLOCK_APP_AUDIO_QUEUE(); } // int t = 0; // t = hal_sys_timer_get(); msbc_encoder_pcmdata.data = temp_msbc_buf; msbc_encoder_pcmdata.dataLen = MSBC_ENCODE_PCM_LEN; memset(temp_msbc_buf1, 0, MSBC_FRAME_SIZE); btif_sbc_encode_frames(msbc_encoder, &msbc_encoder_pcmdata, &bytes_encoded, temp_msbc_buf1, (uint16_t *)&buf_len, 0xFFFF); // TRACE(1,"enc msbc %d t\n", hal_sys_timer_get()-t); // TRACE(2,"encode len %d, out len %d\n", bytes_encoded, buf_len); dest_buf[offset++] = 1 << 8; dest_buf[offset++] = get_msbc_counter() << 8; for (int i = 0; i < buf_len; ++i) { dest_buf[offset++] = temp_msbc_buf1[i] << 8; } dest_buf[offset++] = 0; // padding got_len = len; } #if defined(TX_RX_PCM_MASK) if (btdrv_is_pcm_mask_enable() == 1) { int status; uint8_t len = 120; uint8_t temp_mic_buff[len]; for (uint8_t j = 0; j < len; j++) { temp_mic_buff[j] = buf[2 * j + 1]; } status = APP_AUDIO_EnCQueue(&Tx_esco_queue, temp_mic_buff, len); if (status) { // TRACE(0,"Tx EnC Fail"); } } #endif #endif } else { #if defined(CVSD_BYPASS) got_len = encode_cvsd_frame(buf, len); #else int r = 0; unsigned char *e1 = NULL, *e2 = NULL; unsigned int len1 = 0, len2 = 0; got_len = 0; LOCK_APP_AUDIO_QUEUE(); // size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue); r = APP_AUDIO_PeekCQueue(&voicebtpcm_p2m_pcm_queue, len - got_len, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); // VOICEBTPCM_TRACE(2,"p2m :%d/%d", len, // APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue)); if (r == CQ_OK) { if (len1) { app_audio_memcpy_16bit((short *)buf, (short *)e1, len1 / 2); LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len1); UNLOCK_APP_AUDIO_QUEUE(); got_len += len1; } if (len2 != 0) { app_audio_memcpy_16bit((short *)(buf + got_len), (short *)e2, len2 / 2); got_len += len2; LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_p2m_pcm_queue, 0, len2); UNLOCK_APP_AUDIO_QUEUE(); } } else { VOICEBTPCM_TRACE(0, "mic buff underflow"); app_audio_memset_16bit((short *)buf, 0, len / 2); got_len = len; voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_CACHEING; } #endif } buf += msbc_encode_temp_len; } return got_len; } #if 0 void get_mic_data_max(short *buf, uint32_t len) { int max0 = -32768, min0 = 32767, diff0 = 0; int max1 = -32768, min1 = 32767, diff1 = 0; for(uint32_t i=0; imax0) { max0 = buf[i+0]; } if(buf[i+0]max1) { max1 = buf[i+1]; } if(buf[i+1]48K single phase coef Number:=24, upsample factor:=6, 64, -311, 210, -320, 363, -407, 410, -356, 196, 191,-1369,30721, 3861,-2265, 1680,-1321, 1049, -823, 625, -471, 297, -327, 34, 19, 72, -254, 75, -117, 46, 58, -256, 583,-1141, 2197,-4866,28131,10285,-4611, 2935,-2061, 1489,-1075, 755, -523, 310, -291, -19, 31, 65, -175, -73, 84, -245, 457, -786, 1276,-2040, 3377,-6428,23348,17094,-6200, 3592,-2347, 1588,-1073, 703, -447, 236, -203, -92, 49, 49, -92, -203, 236, -447, 703,-1073, 1588,-2347, 3592,-6200,17094,23348,-6428, 3377,-2040, 1276, -786, 457, -245, 84, -73, -175, 65, 31, -19, -291, 310, -523, 755,-1075, 1489,-2061, 2935,-4611,10285,28131,-4866, 2197,-1141, 583, -256, 58, 46, -117, 75, -254, 72, 19, 34, -327, 297, -471, 625, -823, 1049,-1321, 1680,-2265, 3861,30721,-1369, 191, 196, -356, 410, -407, 363, -320, 210, -311, 64, */ const static short coef_8k_upto_48k[6][US_COEF_NUM] __attribute__(( section(".sram_data"))) = { {64, -311, 210, -320, 363, -407, 410, -356, 196, 191, -1369, 30721, 3861, -2265, 1680, -1321, 1049, -823, 625, -471, 297, -327, 34, 19}, {72, -254, 75, -117, 46, 58, -256, 583, -1141, 2197, -4866, 28131, 10285, -4611, 2935, -2061, 1489, -1075, 755, -523, 310, -291, -19, 31}, {65, -175, -73, 84, -245, 457, -786, 1276, -2040, 3377, -6428, 23348, 17094, -6200, 3592, -2347, 1588, -1073, 703, -447, 236, -203, -92, 49}, {49, -92, -203, 236, -447, 703, -1073, 1588, -2347, 3592, -6200, 17094, 23348, -6428, 3377, -2040, 1276, -786, 457, -245, 84, -73, -175, 65}, {31, -19, -291, 310, -523, 755, -1075, 1489, -2061, 2935, -4611, 10285, 28131, -4866, 2197, -1141, 583, -256, 58, 46, -117, 75, -254, 72}, {19, 34, -327, 297, -471, 625, -823, 1049, -1321, 1680, -2265, 3861, 30721, -1369, 191, 196, -356, 410, -407, 363, -320, 210, -311, 64}}; /* 16K -->48K single phase coef Number:=24, upsample factor:=3, 1, -291, 248, -327, 383, -405, 362, -212, -129, 875,-2948,29344, 7324,-3795, 2603,-1913, 1418,-1031, 722, -478, 292, -220, -86, 16, 26, -212, 6, 45, -185, 414, -764, 1290,-2099, 3470,-6431,20320,20320,-6431, 3470,-2099, 1290, -764, 414, -185, 45, 6, -212, 26, 16, -86, -220, 292, -478, 722,-1031, 1418,-1913, 2603,-3795, 7324,29344,-2948, 875, -129, -212, 362, -405, 383, -327, 248, -291, 1, */ const static short coef_16k_upto_48k[3][US_COEF_NUM] __attribute__(( section(".sram_data"))) = { {1, -291, 248, -327, 383, -405, 362, -212, -129, 875, -2948, 29344, 7324, -3795, 2603, -1913, 1418, -1031, 722, -478, 292, -220, -86, 16}, {26, -212, 6, 45, -185, 414, -764, 1290, -2099, 3470, -6431, 20320, 20320, -6431, 3470, -2099, 1290, -764, 414, -185, 45, 6, -212, 26}, {16, -86, -220, 292, -478, 722, -1031, 1418, -1913, 2603, -3795, 7324, 29344, -2948, 875, -129, -212, 362, -405, 383, -327, 248, -291, 1}}; static short us_para_lst[US_COEF_NUM - 1]; static inline short us_get_coef_para(U32 samp_idx, U32 coef_idx) { if (bt_sco_samplerate_ratio == 6) return coef_8k_upto_48k[samp_idx][coef_idx]; else return coef_16k_upto_48k[samp_idx][coef_idx]; } void us_fir_init(void) { app_audio_memset_16bit(us_para_lst, 0, sizeof(us_para_lst) / sizeof(short)); } __attribute__((section(".fast_text_sram"))) U32 us_fir_run(short *src_buf, short *dst_buf, U32 in_samp_num) { U32 in_idx, samp_idx, coef_idx, real_idx, out_idx; int para, out; for (in_idx = 0, out_idx = 0; in_idx < in_samp_num; in_idx++) { for (samp_idx = 0; samp_idx < bt_sco_samplerate_ratio; samp_idx++) { out = 0; for (coef_idx = 0; coef_idx < US_COEF_NUM; coef_idx++) { real_idx = coef_idx + in_idx; para = (real_idx < (US_COEF_NUM - 1)) ? us_para_lst[real_idx] : src_buf[real_idx - (US_COEF_NUM - 1)]; out += para * us_get_coef_para(samp_idx, coef_idx); } dst_buf[out_idx] = (short)(out >> 16); out_idx++; } } if (in_samp_num >= (US_COEF_NUM - 1)) { app_audio_memcpy_16bit(us_para_lst, (src_buf + in_samp_num - US_COEF_NUM + 1), (US_COEF_NUM - 1)); } else { U32 start_idx = (US_COEF_NUM - 1 - in_samp_num); app_audio_memcpy_16bit(us_para_lst, (us_para_lst + in_samp_num), start_idx); app_audio_memcpy_16bit((us_para_lst + start_idx), src_buf, in_samp_num); } return out_idx; } uint32_t voicebtpcm_pcm_resample(short *src_samp_buf, uint32_t src_smpl_cnt, short *dst_samp_buf) { return us_fir_run(src_samp_buf, dst_samp_buf, src_smpl_cnt); } #endif static int speech_tx_aec_frame_len = 0; int speech_tx_aec_get_frame_len(void) { return speech_tx_aec_frame_len; } void speech_tx_aec_set_frame_len(int len) { TRACE(2, "[%s] len = %d", __func__, len); speech_tx_aec_frame_len = len; } #if 1 // used by capture, store data from mic to memory uint32_t voicebtpcm_pcm_audio_data_come(uint8_t *buf, uint32_t len) { int16_t POSSIBLY_UNUSED ret = 0; bool POSSIBLY_UNUSED vdt = false; int size = 0; #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) uint32_t queue_len; uint32_t len_per_channel = len / SPEECH_CODEC_CAPTURE_CHANNEL_NUM; ASSERT(len_per_channel == speech_tx_aec_get_frame_len() * sizeof(short), "%s: Unmatched len: %u != %u", __func__, len_per_channel, speech_tx_aec_get_frame_len() * sizeof(short)); ASSERT(echo_buf_q_rpos + len_per_channel <= echo_buf_q_size, "%s: rpos (%u) overflow: len=%u size=%u", __func__, echo_buf_q_rpos, len_per_channel, echo_buf_q_size); if (echo_buf_q_rpos == echo_buf_q_wpos) { queue_len = echo_buf_q_full ? echo_buf_q_size : 0; echo_buf_q_full = false; } else if (echo_buf_q_rpos < echo_buf_q_wpos) { queue_len = echo_buf_q_wpos - echo_buf_q_rpos; } else { queue_len = echo_buf_q_size + echo_buf_q_wpos - echo_buf_q_rpos; } ASSERT(queue_len >= len_per_channel, "%s: queue underflow: q_len=%u len=%u rpos=%u wpos=%u size=%u", __func__, queue_len, len_per_channel, echo_buf_q_rpos, echo_buf_q_wpos, echo_buf_q_size); aec_echo_buf = (int16_t *)(echo_buf_queue + echo_buf_q_rpos); echo_buf_q_rpos += len_per_channel; if (echo_buf_q_rpos >= echo_buf_q_size) { echo_buf_q_rpos = 0; } #endif #endif short *pcm_buf = (short *)buf; #if defined(SPEECH_TX_24BIT) int pcm_len = len / sizeof(int32_t); #else int pcm_len = len / sizeof(int16_t); #endif if (app_get_current_overlay() == APP_OVERLAY_HFP) { speech_tx_process(pcm_buf, aec_echo_buf, &pcm_len); #if defined(SPEECH_TX_24BIT) int32_t *buf24 = (int32_t *)pcm_buf; int16_t *buf16 = (int16_t *)pcm_buf; for (int i = 0; i < pcm_len; i++) buf16[i] = (buf24[i] >> 8); #endif if (resample_needed_flag == true) { iir_resample_process(upsample_st, pcm_buf, upsample_buf_for_msbc, pcm_len); pcm_buf = upsample_buf_for_msbc; pcm_len = sco_frame_length; } } else { memset(buf, 0, len); } LOCK_APP_AUDIO_QUEUE(); store_voicebtpcm_p2m_buffer((uint8_t *)pcm_buf, pcm_len * sizeof(short)); size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_pcm_queue); UNLOCK_APP_AUDIO_QUEUE(); if (size >= voicebtpcm_p2m_cache_threshold) { voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_OK; } return pcm_len * 2; } #else // used by capture, store data from mic to memory uint32_t voicebtpcm_pcm_audio_data_come(uint8_t *buf, uint32_t len) { int16_t POSSIBLY_UNUSED ret = 0; bool POSSIBLY_UNUSED vdt = false; int size = 0; short *pcm_buf = (short *)buf; uint32_t pcm_len = len / 2; // TRACE(2,"[%s] pcm_len = %d", __func__, pcm_len); LOCK_APP_AUDIO_QUEUE(); store_voicebtpcm_p2m_buffer((uint8_t *)pcm_buf, pcm_len * 2); size = APP_AUDIO_LengthOfCQueue(&voicebtpcm_p2m_queue); UNLOCK_APP_AUDIO_QUEUE(); if (size > VOICEBTPCM_PCM_TEMP_BUFFER_SIZE) { voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_OK; } return pcm_len * 2; } #endif // used by playback, play data from memory to speaker uint32_t voicebtpcm_pcm_audio_more_data(uint8_t *buf, uint32_t len) { uint32_t l = 0; // TRACE(3,"[%s]: pcm_len = %d, %d", __FUNCTION__, len / 2, // FAST_TICKS_TO_US(hal_fast_sys_timer_get())); if ((voicebtpcm_cache_m2p_status == APP_AUDIO_CACHE_CACHEING) || (app_get_current_overlay() != APP_OVERLAY_HFP)) { app_audio_memset_16bit((short *)buf, 0, len / 2); l = len; } else { #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) || \ defined(SPEECH_TX_THIRDPARTY) #if !(defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE)) #if defined(SPEECH_TX_24BIT) && defined(SPEECH_RX_24BIT) memcpy(aec_echo_buf, buf, len / sizeof(int16_t) * sizeof(int32_t)); #elif defined(SPEECH_TX_24BIT) && !defined(SPEECH_RX_24BIT) short *buf_p = (short *)buf; for (uint32_t i = 0; i < len / sizeof(int16_t); i++) { aec_echo_buf[i] = ((int32_t)buf_p[i] << 8); } #elif !defined(SPEECH_TX_24BIT) && defined(SPEECH_RX_24BIT) int32_t *buf32_p = (int32_t *)buf; for (uint32_t i = 0; i < len / sizeof(int16_t); i++) { aec_echo_buf[i] = (buf32_p[i] >> 8); } #else app_audio_memcpy_16bit((int16_t *)aec_echo_buf, (int16_t *)buf, len / 2); #endif #endif #endif int decode_len = len; uint8_t *decode_buf = buf; if (resample_needed_flag == true) { decode_len = sco_frame_length * 2; decode_buf = (uint8_t *)downsample_buf_for_msbc; } unsigned int len1 = 0, len2 = 0; unsigned char *e1 = NULL, *e2 = NULL; int r = 0; LOCK_APP_AUDIO_QUEUE(); len1 = len2 = 0; e1 = e2 = 0; r = APP_AUDIO_PeekCQueue(&voicebtpcm_m2p_pcm_queue, decode_len, &e1, &len1, &e2, &len2); UNLOCK_APP_AUDIO_QUEUE(); if (r == CQ_ERR) { TRACE(0, "pcm buff underflow"); memset(decode_buf, 0, decode_len); l = len; goto fail; } if (!len1) { TRACE(2, "pcm len1 underflow %d/%d\n", len1, len2); memset(decode_buf, 0, decode_len); l = len; goto fail; } if (len1 > 0 && e1) { memcpy(decode_buf, e1, len1); } if (len2 > 0 && e2) { memcpy(decode_buf + len1, e2, len2); } LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_DeCQueue(&voicebtpcm_m2p_pcm_queue, 0, decode_len); UNLOCK_APP_AUDIO_QUEUE(); } // if (voicebtpcm_cache_m2p_status == APP_AUDIO_CACHE_CACHEING) // downsample_buf_for_msbc size is len * 2 if (resample_needed_flag == true) { iir_resample_process(downsample_st, downsample_buf_for_msbc, (int16_t *)buf, sco_frame_length); } fail: short *POSSIBLY_UNUSED pcm_buf = (short *)buf; int POSSIBLY_UNUSED pcm_len = len / 2; #if defined(SPEECH_RX_24BIT) int32_t *buf32 = (int32_t *)buf; for (int i = pcm_len - 1; i >= 0; i--) { buf32[i] = ((int32_t)pcm_buf[i] << 8); } #endif speech_rx_process(pcm_buf, &pcm_len); buf = (uint8_t *)pcm_buf; len = pcm_len * sizeof(short); #if defined(SPEECH_RX_24BIT) len = len / sizeof(int16_t) * sizeof(int32_t); #endif #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) uint32_t queue_len; ASSERT(len == speech_tx_aec_get_frame_len() * sizeof(short), "%s: Unmatched len: %u != %u", __func__, len, speech_tx_aec_get_frame_len() * sizeof(short)); ASSERT(echo_buf_q_wpos + len <= echo_buf_q_size, "%s: wpos (%u) overflow: len=%u size=%u", __func__, echo_buf_q_wpos, len, echo_buf_q_size); if (echo_buf_q_rpos == echo_buf_q_wpos) { queue_len = echo_buf_q_full ? echo_buf_q_size : 0; } else if (echo_buf_q_rpos < echo_buf_q_wpos) { queue_len = echo_buf_q_wpos - echo_buf_q_rpos; } else { queue_len = echo_buf_q_size + echo_buf_q_wpos - echo_buf_q_rpos; } ASSERT(queue_len + len <= echo_buf_q_size, "%s: queue overflow: q_len=%u len=%u rpos=%u wpos=%u size=%u", __func__, queue_len, len, echo_buf_q_rpos, echo_buf_q_wpos, echo_buf_q_size); app_audio_memcpy_16bit((int16_t *)(echo_buf_queue + echo_buf_q_wpos), (int16_t *)buf, len / 2); echo_buf_q_wpos += len; if (echo_buf_q_wpos >= echo_buf_q_size) { echo_buf_q_wpos = 0; } if (echo_buf_q_rpos == echo_buf_q_wpos) { echo_buf_q_full = true; } #endif #endif return l; } void *voicebtpcm_get_ext_buff(int size) { uint8_t *pBuff = NULL; if (size % 4) { size = size + (4 - size % 4); } app_audio_mempool_get_buff(&pBuff, size); VOICEBTPCM_TRACE(2, "[%s] len:%d", __func__, size); return (void *)pBuff; } int voicebtpcm_pcm_echo_buf_queue_init(uint32_t size) { #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) echo_buf_queue = (uint8_t *)voicebtpcm_get_ext_buff(size); echo_buf_q_size = size; echo_buf_q_wpos = 0; echo_buf_q_rpos = 0; echo_buf_q_full = false; #endif #endif return 0; } void voicebtpcm_pcm_echo_buf_queue_reset(void) { #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) echo_buf_q_wpos = 0; echo_buf_q_rpos = 0; echo_buf_q_full = false; #endif #endif } void voicebtpcm_pcm_echo_buf_queue_deinit(void) { #if defined(SPEECH_TX_AEC) || defined(SPEECH_TX_AEC2) || \ defined(SPEECH_TX_AEC3) || defined(SPEECH_TX_AEC2FLOAT) #if defined(__AUDIO_RESAMPLE__) && defined(SW_SCO_RESAMPLE) echo_buf_queue = NULL; echo_buf_q_size = 0; echo_buf_q_wpos = 0; echo_buf_q_rpos = 0; echo_buf_q_full = false; #endif #endif } extern enum AUD_SAMPRATE_T speech_codec_get_sample_rate(void); // sco sample rate: encoder/decoder sample rate // codec sample rate: hardware sample rate int voicebtpcm_pcm_audio_init(int sco_sample_rate, int codec_sample_rate) { uint8_t POSSIBLY_UNUSED *speech_buf = NULL; int POSSIBLY_UNUSED speech_len = 0; sco_frame_length = SPEECH_FRAME_MS_TO_LEN(sco_sample_rate, SPEECH_SCO_FRAME_MS); codec_frame_length = SPEECH_FRAME_MS_TO_LEN(codec_sample_rate, SPEECH_SCO_FRAME_MS); TRACE(3, "[%s] TX: sample rate = %d, frame len = %d", __func__, codec_sample_rate, codec_frame_length); TRACE(3, "[%s] RX: sample rate = %d, frame len = %d", __func__, codec_sample_rate, codec_frame_length); // init cqueue uint8_t *p2m_pcm_buff = NULL; uint8_t *m2p_pcm_buff = NULL; #if defined(TX_RX_PCM_MASK) uint8_t *Mic_frame_buff = NULL; uint8_t *Rx_esco_buff = NULL; uint32_t pcm_buf_size = 240 * sizeof(uint8_t); #endif if (bt_sco_codec_is_msbc()) { voicebtpcm_p2m_pcm_cache_size = VOICEBTPCM_PCM_16K_QUEUE_SIZE; voicebtpcm_m2p_pcm_cache_size = VOICEBTPCM_PCM_16K_QUEUE_SIZE; } else { voicebtpcm_p2m_pcm_cache_size = VOICEBTPCM_PCM_8K_QUEUE_SIZE; voicebtpcm_m2p_pcm_cache_size = VOICEBTPCM_PCM_8K_QUEUE_SIZE; } voicebtpcm_p2m_cache_threshold = voicebtpcm_p2m_pcm_cache_size / 2; voicebtpcm_m2p_cache_threshold = voicebtpcm_m2p_pcm_cache_size / 2; app_audio_mempool_get_buff(&p2m_pcm_buff, voicebtpcm_p2m_pcm_cache_size); app_audio_mempool_get_buff(&m2p_pcm_buff, voicebtpcm_m2p_pcm_cache_size); #if defined(TX_RX_PCM_MASK) app_audio_mempool_get_buff(&Mic_frame_buff, pcm_buf_size); app_audio_mempool_get_buff(&Rx_esco_buff, pcm_buf_size); #endif LOCK_APP_AUDIO_QUEUE(); APP_AUDIO_InitCQueue(&voicebtpcm_p2m_pcm_queue, voicebtpcm_p2m_pcm_cache_size, p2m_pcm_buff); APP_AUDIO_InitCQueue(&voicebtpcm_m2p_pcm_queue, voicebtpcm_m2p_pcm_cache_size, m2p_pcm_buff); #if defined(TX_RX_PCM_MASK) APP_AUDIO_InitCQueue(&Tx_esco_queue, pcm_buf_size, Mic_frame_buff); APP_AUDIO_InitCQueue(&Rx_esco_queue, pcm_buf_size, Rx_esco_buff); #endif UNLOCK_APP_AUDIO_QUEUE(); voicebtpcm_cache_m2p_status = APP_AUDIO_CACHE_CACHEING; voicebtpcm_cache_p2m_status = APP_AUDIO_CACHE_CACHEING; #if defined(HFP_1_6_ENABLE) memset(DecPcmBuf, 0, SAMPLES_LEN_PER_FRAME * sizeof(short)); memset(DecMsbcBuf, 0, MSBC_LEN_PER_FRAME * sizeof(unsigned char)); memset(DecMsbcBufAll, 0, sizeof(DecMsbcBufAll)); if (bt_sco_codec_is_msbc()) { app_audio_mempool_get_buff((uint8_t **)&msbc_encoder, sizeof(btif_sbc_encoder_t)); #if !defined(PENDING_MSBC_DECODER_ALG) app_audio_mempool_get_buff(&temp_msbc_buf, MSBC_ENCODE_PCM_LEN); app_audio_mempool_get_buff(&temp_msbc_buf1, MSBC_FRAME_SIZE); #else app_audio_mempool_get_buff(&msbc_buf_before_decode, MSBC_FRAME_SIZE * sizeof(short)); app_audio_mempool_get_buff(&temp_msbc_buf, MSBC_ENCODE_PCM_LEN * sizeof(short)); app_audio_mempool_get_buff(&temp_msbc_buf1, MSBC_ENCODE_PCM_LEN * sizeof(short)); #endif // init msbc encoder btif_sbc_init_encoder(msbc_encoder); msbc_encoder->streamInfo.mSbcFlag = 1; msbc_encoder->streamInfo.numChannels = 1; msbc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO; msbc_encoder->streamInfo.bitPool = 26; msbc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; msbc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS; msbc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS; msbc_encoder->streamInfo.numSubBands = 8; msbc_counter = 0x08; // init msbc decoder 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 i; for (i = 0; i < sizeof(msbc_eq_band_gain) / sizeof(float); i++) { msbc_eq_band_gain[i] = EQLevel[cfg_aud_eq_sbc_band_settings[i] + 12]; } btif_sbc_init_decoder(&msbc_decoder); msbc_decoder.streamInfo.mSbcFlag = 1; msbc_decoder.streamInfo.bitPool = 26; msbc_decoder.streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; msbc_decoder.streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO; msbc_decoder.streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS; /* Number of blocks used to encode the stream (4, 8, 12, or 16) */ msbc_decoder.streamInfo.numBlocks = BTIF_MSBC_BLOCKS; /* The number of subbands in the stream (4 or 8) */ msbc_decoder.streamInfo.numSubBands = 8; msbc_decoder.streamInfo.numChannels = 1; #if defined(PENDING_MSBC_DECODER_ALG) last_msbc_sync_num = 0; APP_AUDIO_InitCQueue(&msbc_temp_queue, sizeof(DecMsbcBufAll), (uint8_t *)DecMsbcBufAll); #endif // init msbc plc #ifndef ENABLE_LPC_PLC InitPLC(&msbc_plc_state); #endif next_frame_flag = 0; msbc_find_first_sync = 0; packet_loss_detection_init(&pld); #if defined(ENABLE_PLC_ENCODER) app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder, sizeof(btif_sbc_encoder_t)); btif_sbc_init_encoder(msbc_plc_encoder); msbc_plc_encoder->streamInfo.mSbcFlag = 1; msbc_plc_encoder->streamInfo.bitPool = 26; msbc_plc_encoder->streamInfo.sampleFreq = BTIF_SBC_CHNL_SAMPLE_FREQ_16; msbc_plc_encoder->streamInfo.channelMode = BTIF_SBC_CHNL_MODE_MONO; msbc_plc_encoder->streamInfo.allocMethod = BTIF_SBC_ALLOC_METHOD_LOUDNESS; /* Number of blocks used to encode the stream (4, 8, 12, or 16) */ msbc_plc_encoder->streamInfo.numBlocks = BTIF_MSBC_BLOCKS; /* The number of subbands in the stream (4 or 8) */ msbc_plc_encoder->streamInfo.numSubBands = 8; msbc_plc_encoder->streamInfo.numChannels = 1; app_audio_mempool_get_buff((uint8_t **)&msbc_plc_encoder_buffer, sizeof(int16_t) * (SAMPLES_LEN_PER_FRAME + MSBC_CODEC_DELAY)); #endif } else #endif { speech_plc = (PlcSt_8000 *)speech_plc_8000_init(voicebtpcm_get_ext_buff); } #if defined(CVSD_BYPASS) Pcm8k_CvsdInit(); #endif #ifdef SPEECH_RX_PLC_DUMP_DATA audio_dump_temp_buf = (int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * 120); audio_dump_init(120, sizeof(short), 3); #endif resample_needed_flag = (sco_sample_rate == codec_sample_rate) ? 0 : 1; if (resample_needed_flag == true) { // upsample_buf_for_msbc -> uplink resampler // downsample_buf_for_msbc -> downlink resampler // store msbc pcm buffer upsample_buf_for_msbc = (int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * sco_frame_length); downsample_buf_for_msbc = (int16_t *)voicebtpcm_get_ext_buff(sizeof(int16_t) * sco_frame_length); } #if defined(SCO_OPTIMIZE_FOR_RAM) sco_overlay_ram_buf_len = hal_overlay_get_text_free_size((enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP); sco_overlay_ram_buf = (uint8_t *)hal_overlay_get_text_free_addr( (enum HAL_OVERLAY_ID_T)APP_OVERLAY_HFP); #endif speech_len = app_audio_mempool_free_buff_size() - APP_BT_STREAM_USE_BUF_SIZE; speech_buf = (uint8_t *)voicebtpcm_get_ext_buff(speech_len); int tx_frame_ms = SPEECH_PROCESS_FRAME_MS; int rx_frame_ms = SPEECH_PROCESS_FRAME_MS; #if !defined(SPEECH_RX_NS2FLOAT) rx_frame_ms = SPEECH_SCO_FRAME_MS; #endif speech_init(codec_sample_rate, codec_sample_rate, tx_frame_ms, rx_frame_ms, SPEECH_SCO_FRAME_MS, speech_buf, speech_len); if (resample_needed_flag == true) { // Resample state must be created after speech init, as it uses speech heap upsample_st = iir_resample_init( codec_frame_length, iir_resample_choose_mode(codec_sample_rate, sco_sample_rate)); downsample_st = iir_resample_init( sco_frame_length, iir_resample_choose_mode(sco_sample_rate, codec_sample_rate)); } #if defined(HFP_1_6_ENABLE) && defined(ENABLE_LPC_PLC) msbc_plc_state = lpc_plc_create(sco_sample_rate); #endif return 0; } int voicebtpcm_pcm_audio_deinit(void) { TRACE(1, "[%s] Close...", __func__); // TRACE(2,"[%s] app audio buffer free = %d", __func__, // app_audio_mempool_free_buff_size()); #if defined(HFP_1_6_ENABLE) && defined(ENABLE_LPC_PLC) lpc_plc_destroy(msbc_plc_state); #endif if (resample_needed_flag == true) { iir_resample_destroy(upsample_st); iir_resample_destroy(downsample_st); } speech_deinit(); #if defined(HFP_1_6_ENABLE) #if !defined(PENDING_MSBC_DECODER_ALG) packet_loss_detection_report(&pld); #endif #endif #if defined(SCO_OPTIMIZE_FOR_RAM) sco_overlay_ram_buf = NULL; sco_overlay_ram_buf_len = 0; #endif voicebtpcm_pcm_echo_buf_queue_deinit(); // TRACE(1,"Free buf = %d", app_audio_mempool_free_buff_size()); return 0; }