/*************************************************************************** * * 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 "cmsis.h" #include "cmsis_os.h" #include "plat_types.h" #include #include "heap_api.h" #include "hal_location.h" #include "hal_timer.h" #include "audioflinger.h" #include "app_bt_media_manager.h" #include "app_bt.h" #include "bt_drv_reg_op.h" #include "app_audio.h" #include "codec_sbc.h" #include "avdtp_api.h" #include "a2dp_decoder.h" #include "a2dp_decoder_internal.h" #if defined(IBRT) #include "btapp.h" #include "bt_drv_interface.h" #include "app_ibrt_if.h" #include "app_tws_ctrl_thread.h" #include "app_tws_ibrt_cmd_handler.h" #include "app_tws_ibrt_audio_analysis.h" #include "app_tws_ibrt_audio_sync.h" #endif #include "crc32.h" #include "audio_prompt_sbc.h" #ifndef A2DP_AUDIO_MEMPOOL_SIZE #if defined(A2DP_LDAC_ON) #define A2DP_AUDIO_LDAC_MEMPOOL_SIZE (76*1024) #endif #define A2DP_AUDIO_MEMPOOL_SIZE (72*1024) #endif #define A2DP_AUDIO_WAIT_TIMEOUT_MS (500) #define A2DP_AUDIO_MUTE_FRAME_CNT_AFTER_NO_CACHE (25) #define A2DP_AUDIO_SKIP_FRAME_LIMIT_AFTER_NO_CACHE (50) #define A2DP_AUDIO_REFILL_AFTER_NO_CACHE (1) #ifdef __A2DP_AUDIO_SYNC_FIX_DIFF_NOPID__ #define A2DP_AUDIO_SYNC_INTERVAL (25) #else #define A2DP_AUDIO_SYNC_INTERVAL (1000) #endif #define A2DP_AUDIO_LATENCY_LOW_FACTOR (1.0f) #define A2DP_AUDIO_LATENCY_HIGH_FACTOR (1.6f) #define A2DP_AUDIO_LATENCY_MORE_FACTOR (1.2f) #define A2DP_AUDIO_SYNC_FACTOR_REFERENCE (1.0f) #define A2DP_AUDIO_SYNC_FACTOR_FAST_LIMIT ( 0.00015f) #define A2DP_AUDIO_SYNC_FACTOR_SLOW_LIMIT (-0.00035f) #define A2DP_AUDIO_SYNC_FACTOR_NEED_FAST_CACHE (-0.001f) #define A2DP_AUDIO_UNDERFLOW_CAUSE_AUDIO_RETRIGGER (1) extern A2DP_AUDIO_DECODER_T a2dp_audio_sbc_decoder_config; #if defined(A2DP_AAC_ON) extern A2DP_AUDIO_DECODER_T a2dp_audio_aac_lc_decoder_config; #endif #if defined(A2DP_LHDC_ON) extern A2DP_AUDIO_DECODER_T a2dp_audio_lhdc_decoder_config; #endif #if defined(A2DP_LDAC_ON) extern A2DP_AUDIO_DECODER_T a2dp_audio_ldac_decoder_config; #endif #if defined(A2DP_SCALABLE_ON) extern A2DP_AUDIO_DECODER_T a2dp_audio_scalable_decoder_config; #endif osSemaphoreDef(audio_buffer_semaphore); osMutexDef(audio_buffer_mutex); osMutexDef(audio_status_mutex); osMutexDef(audio_stop_mutex); #ifdef __A2DP_AUDIO_SYNC_FIX_DIFF_NOPID__ //#define A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT (1) #define A2DP_AUDIO_SYNC_FIX_DIFF_INTERVAL (640) #define A2DP_AUDIO_SYNC_FIX_DIFF_FAST_LIMIT ( 0.003f) #define A2DP_AUDIO_SYNC_FIX_DIFF_SLOW_LIMIT (-0.003f) extern uint32_t app_bt_stream_get_dma_buffer_samples(void); static int a2dp_audio_sync_fix_diff_proc(uint32_t tick); static int a2dp_audio_sync_fix_diff_stop(uint32_t tick); static int32_t a2dp_audio_sync_fix_diff_reset(void); static int32_t a2dp_audio_sync_fix_diff_start(uint32_t tick); typedef enum{ A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_IDLE, A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_START, A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_STOP, }A2DP_AUDIO_SYNC_FIX_DIFF_STATUS; typedef struct { int32_t tick; A2DP_AUDIO_SYNC_FIX_DIFF_STATUS status; }A2DP_AUDIO_SYNC_FIX_DIFF_T; static A2DP_AUDIO_SYNC_FIX_DIFF_T a2dp_audio_sync_fix_diff; #endif A2DP_AUDIO_CONTEXT_T a2dp_audio_context; static heap_handle_t a2dp_audio_heap; static A2DP_AUDIO_LASTFRAME_INFO_T a2dp_audio_lastframe_info; static A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK a2dp_audio_detect_next_packet_callback = NULL; static A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK a2dp_audio_store_packet_callback = NULL; static float a2dp_audio_latency_factor = A2DP_AUDIO_LATENCY_LOW_FACTOR; static float sync_tune_dest_ratio = 1.0f; static uint32_t store_packet_history_loctime = 0; static uint32_t check_sum_seed = 0; static int a2dp_audio_internal_lastframe_info_ptr_get(A2DP_AUDIO_LASTFRAME_INFO_T **lastframe_info); float a2dp_audio_get_sample_reference(void); int8_t a2dp_audio_get_current_buf_size(void); void a2dp_audio_heap_init(void *begin_addr, uint32_t size) { a2dp_audio_heap = heap_register(begin_addr,size); } void *a2dp_audio_heap_malloc(uint32_t size) { void *ptr = heap_malloc(a2dp_audio_heap,size); ASSERT_A2DP_DECODER(ptr, "%s size:%d", __func__, size); return ptr; } void *a2dp_audio_heap_cmalloc(uint32_t size) { void *ptr = heap_malloc(a2dp_audio_heap,size); ASSERT_A2DP_DECODER(ptr, "%s size:%d", __func__, size); memset(ptr, 0, size); return ptr; } void *a2dp_audio_heap_realloc(void *rmem, uint32_t newsize) { void *ptr = heap_realloc(a2dp_audio_heap, rmem, newsize); ASSERT_A2DP_DECODER(ptr, "%s rmem:%p size:%d", __func__, rmem,newsize); return ptr; } void a2dp_audio_heap_free(void *rmem) { ASSERT_A2DP_DECODER(rmem, "%s rmem:%p", __func__, rmem); heap_free(a2dp_audio_heap,rmem); } void a2dp_audio_heap_info(size_t *total, size_t *used, size_t *max_used) { multi_heap_info_t info; heap_get_info(a2dp_audio_heap, &info); if (total != NULL) *total = info.total_bytes; if (used != NULL) *used = info.total_allocated_bytes; if (max_used != NULL) *max_used = info.total_bytes - info.minimum_free_bytes; } int inline a2dp_audio_semaphore_init(void) { if (a2dp_audio_context.audio_semaphore.semaphore == NULL){ a2dp_audio_context.audio_semaphore.semaphore = osSemaphoreCreate(osSemaphore(audio_buffer_semaphore), 0); } a2dp_audio_context.audio_semaphore.enalbe = false; return 0; } int inline a2dp_audio_buffer_mutex_init(void) { if (a2dp_audio_context.audio_buffer_mutex == NULL){ a2dp_audio_context.audio_buffer_mutex = osMutexCreate((osMutex(audio_buffer_mutex))); } return 0; } int inline a2dp_audio_buffer_mutex_lock(void) { osMutexWait((osMutexId)a2dp_audio_context.audio_buffer_mutex, osWaitForever); return 0; } int inline a2dp_audio_buffer_mutex_unlock(void) { osMutexRelease((osMutexId)a2dp_audio_context.audio_buffer_mutex); return 0; } int inline a2dp_audio_status_mutex_init(void) { if (a2dp_audio_context.audio_status_mutex == NULL){ a2dp_audio_context.audio_status_mutex = osMutexCreate((osMutex(audio_status_mutex))); } return 0; } int inline a2dp_audio_status_mutex_lock(void) { osMutexWait((osMutexId)a2dp_audio_context.audio_status_mutex, osWaitForever); return 0; } int inline a2dp_audio_status_mutex_unlock(void) { osMutexRelease((osMutexId)a2dp_audio_context.audio_status_mutex); return 0; } int inline a2dp_audio_semaphore_wait(uint32_t timeout_ms) { osSemaphoreId semaphore_id = (osSemaphoreId)a2dp_audio_context.audio_semaphore.semaphore; a2dp_audio_buffer_mutex_lock(); a2dp_audio_context.audio_semaphore.enalbe = true; a2dp_audio_buffer_mutex_unlock(); int32_t nRet = osSemaphoreWait(semaphore_id, timeout_ms); if ((0 == nRet) || (-1 == nRet)){ TRACE_A2DP_DECODER_W("%s wait timerout", __func__); return -1; } return 0; } int inline a2dp_audio_semaphore_release(void) { bool enalbe = false; a2dp_audio_buffer_mutex_lock(); if (a2dp_audio_context.audio_semaphore.enalbe){ a2dp_audio_context.audio_semaphore.enalbe = false; enalbe = true; } a2dp_audio_buffer_mutex_unlock(); if (enalbe){ osSemaphoreId semaphore_id = (osSemaphoreId)a2dp_audio_context.audio_semaphore.semaphore; osSemaphoreRelease(semaphore_id); } return 0; } list_node_t *a2dp_audio_list_begin(const list_t *list) { a2dp_audio_buffer_mutex_lock(); list_node_t *node = list_begin(list); a2dp_audio_buffer_mutex_unlock(); return node; } list_node_t *a2dp_audio_list_end(const list_t *list) { a2dp_audio_buffer_mutex_lock(); list_node_t *node = list_end(list); a2dp_audio_buffer_mutex_unlock(); return node; } uint32_t a2dp_audio_list_length(const list_t *list) { a2dp_audio_buffer_mutex_lock(); uint32_t length = list_length(list); a2dp_audio_buffer_mutex_unlock(); return length; } void *a2dp_audio_list_node(const list_node_t *node) { a2dp_audio_buffer_mutex_lock(); void *data = list_node(node); a2dp_audio_buffer_mutex_unlock(); return data; } list_node_t *a2dp_audio_list_next(const list_node_t *node) { a2dp_audio_buffer_mutex_lock(); list_node_t *next =list_next(node); a2dp_audio_buffer_mutex_unlock(); return next; } bool a2dp_audio_list_remove(list_t *list, void *data) { a2dp_audio_buffer_mutex_lock(); bool nRet = list_remove(list, data); a2dp_audio_buffer_mutex_unlock(); return nRet; } bool a2dp_audio_list_append(list_t *list, void *data) { a2dp_audio_buffer_mutex_lock(); bool nRet = list_append(list, data); a2dp_audio_buffer_mutex_unlock(); return nRet; } void a2dp_audio_list_clear(list_t *list) { a2dp_audio_buffer_mutex_lock(); list_clear(list); a2dp_audio_buffer_mutex_unlock(); } void a2dp_audio_list_free(list_t *list) { a2dp_audio_buffer_mutex_lock(); list_free(list); a2dp_audio_buffer_mutex_unlock(); } list_t *a2dp_audio_list_new(list_free_cb callback, list_mempool_zmalloc zmalloc, list_mempool_free free) { a2dp_audio_buffer_mutex_lock(); list_t *list =list_new(callback, zmalloc, free); a2dp_audio_buffer_mutex_unlock(); return list; } uint32_t a2dp_audio_get_passed(uint32_t curr_ticks, uint32_t prev_ticks, uint32_t max_ticks) { if(curr_ticks < prev_ticks) return ((max_ticks - prev_ticks + 1) + curr_ticks); else return (curr_ticks - prev_ticks); } #ifdef A2DP_CP_ACCEL extern "C" uint32_t get_in_cp_frame_cnt(void); extern "C" uint32_t get_in_cp_frame_delay(void); #else static uint32_t get_in_cp_frame_cnt(void) { return 0; } static uint32_t get_in_cp_frame_delay(void) { return 0; } #endif int inline a2dp_audio_set_status(enum A2DP_AUDIO_DECODER_STATUS decoder_status) { a2dp_audio_status_mutex_lock(); a2dp_audio_context.audio_decoder_status = decoder_status; a2dp_audio_status_mutex_unlock(); return 0; } enum A2DP_AUDIO_DECODER_STATUS inline a2dp_audio_get_status(void) { enum A2DP_AUDIO_DECODER_STATUS decoder_status; a2dp_audio_status_mutex_lock(); decoder_status = a2dp_audio_context.audio_decoder_status; a2dp_audio_status_mutex_unlock(); return decoder_status; } int inline a2dp_audio_set_store_packet_status(enum A2DP_AUDIO_DECODER_STORE_PACKET_STATUS store_packet_status) { a2dp_audio_status_mutex_lock(); a2dp_audio_context.store_packet_status = store_packet_status; a2dp_audio_status_mutex_unlock(); return 0; } enum A2DP_AUDIO_DECODER_STORE_PACKET_STATUS inline a2dp_audio_get_store_packet_status(void) { enum A2DP_AUDIO_DECODER_STORE_PACKET_STATUS store_packet_status; a2dp_audio_status_mutex_lock(); store_packet_status = a2dp_audio_context.store_packet_status; a2dp_audio_status_mutex_unlock(); return store_packet_status; } int inline a2dp_audio_set_playback_status(enum A2DP_AUDIO_DECODER_PLAYBACK_STATUS playback_status) { a2dp_audio_status_mutex_lock(); a2dp_audio_context.playback_status = playback_status; a2dp_audio_status_mutex_unlock(); return 0; } enum A2DP_AUDIO_DECODER_PLAYBACK_STATUS inline a2dp_audio_get_playback_status(void) { enum A2DP_AUDIO_DECODER_PLAYBACK_STATUS playback_status; a2dp_audio_status_mutex_lock(); playback_status = a2dp_audio_context.playback_status; a2dp_audio_status_mutex_unlock(); return playback_status; } static void a2dp_decoder_info_checker(void) { // app_bt_start_custom_function_in_app_thread(0, 0, (uint32_t)bt_drv_reg_op_bt_info_checker); } int a2dp_audio_sync_pid_config(void) { A2DP_AUDIO_SYNC_T *audio_sync = &a2dp_audio_context.audio_sync; A2DP_AUDIO_SYNC_PID_T *pid = &audio_sync->pid; pid->proportiongain = 0.4f; pid->integralgain = 0.1f; pid->derivativegain = 0.6f; return 0; } int a2dp_audio_sync_reset_data(void) { A2DP_AUDIO_SYNC_T *audio_sync = &a2dp_audio_context.audio_sync; a2dp_audio_status_mutex_lock(); audio_sync->tick = 0; audio_sync->cnt = 0; a2dp_audio_sync_pid_config(); #ifdef __A2DP_AUDIO_SYNC_FIX_DIFF_NOPID__ a2dp_audio_sync_fix_diff_reset(); #endif a2dp_audio_status_mutex_unlock(); TRACE_A2DP_DECODER_I("[SYNC]reset_data"); return 0; } int a2dp_audio_sync_init(double ratio) { #ifdef __A2DP_AUDIO_SYNC_FIX_DIFF_NOPID__ a2dp_audio_sync_fix_diff_reset(); #endif a2dp_audio_sync_reset_data(); a2dp_audio_sync_tune_sample_rate(ratio); sync_tune_dest_ratio = (float)ratio; return 0; } int a2dp_audio_sync_tune_sample_rate(double ratio) { float resample_rate_ratio; bool need_tune = false; a2dp_audio_status_mutex_lock(); if (a2dp_audio_context.output_cfg.factor_reference != (float)ratio){ a2dp_audio_context.output_cfg.factor_reference = (float)ratio; resample_rate_ratio = (float)(ratio - (double)1.0); need_tune = true; } //a2dp_audio_status_mutex_unlock(); if (need_tune){ app_audio_manager_tune_samplerate_ratio(AUD_STREAM_PLAYBACK, resample_rate_ratio); TRACE_A2DP_DECODER_I("[SYNC] ppb:%d ratio:%08d", (int32_t)(resample_rate_ratio * 10000000), (int32_t)(ratio * 10000000)); } a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_sync_direct_tune_sample_rate(double ratio) { float resample_rate_ratio; bool need_tune = false; a2dp_audio_status_mutex_lock(); if (a2dp_audio_context.output_cfg.factor_reference != (float)ratio){ a2dp_audio_context.output_cfg.factor_reference = (float)ratio; resample_rate_ratio = (float)(ratio - (double)1.0); need_tune = true; } if (need_tune){ af_codec_direct_tune(AUD_STREAM_PLAYBACK, resample_rate_ratio); TRACE_A2DP_DECODER_I("[SYNC] ppb:%d ratio:%08d", (int32_t)(resample_rate_ratio * 10000000), (int32_t)(ratio * 10000000)); } a2dp_audio_status_mutex_unlock(); return 0; } bool a2dp_audio_sync_tune_onprocess(void) { bool nRet = false;; if (a2dp_audio_context.output_cfg.factor_reference != sync_tune_dest_ratio){ nRet = true; } return nRet; } int a2dp_audio_sync_tune(float ratio) { int nRet = 0; if (sync_tune_dest_ratio == ratio){ goto exit; } sync_tune_dest_ratio = ratio; #if defined(IBRT) if (app_ibrt_ui_is_profile_exchanged()){ if (app_tws_ibrt_mobile_link_connected()){ APP_TWS_IBRT_AUDIO_SYNC_TUNE_T sync_tune; sync_tune.factor_reference = ratio; if (!app_tws_ibrt_audio_sync_tune_need_skip()){ tws_ctrl_send_cmd(APP_TWS_CMD_SYNC_TUNE, (uint8_t*)&sync_tune, sizeof(APP_TWS_IBRT_AUDIO_SYNC_TUNE_T)); }else{ a2dp_audio_sync_tune_cancel(); nRet = -1; } } }else{ a2dp_audio_sync_tune_sample_rate(ratio); } #else a2dp_audio_sync_tune_sample_rate(ratio); #endif exit: return nRet; } int a2dp_audio_sync_tune_cancel(void) { sync_tune_dest_ratio = a2dp_audio_context.output_cfg.factor_reference; return 0; } float a2dp_audio_sync_pid_calc(A2DP_AUDIO_SYNC_PID_T *pid, float diff) { float increment; float pError,dError,iError; pid->error[0] = diff; pError=pid->error[0]-pid->error[1]; iError=pid->error[0]; dError=pid->error[0]-2*pid->error[1]+pid->error[2]; increment = pid->proportiongain*pError+pid->integralgain*iError+pid->derivativegain*dError; pid->error[2] = pid->error[1]; pid->error[1] = pid->error[0]; pid->result += increment; return pid->result; } #ifdef __A2DP_AUDIO_SYNC_FIX_DIFF_NOPID__ static int a2dp_audio_sync_fix_diff_proc(uint32_t tick) { if (a2dp_audio_sync_fix_diff.status == A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_START){ if (a2dp_audio_sync_fix_diff.tick > 0){ a2dp_audio_sync_fix_diff.tick--; }else{ a2dp_audio_sync_fix_diff_stop(0); } } return 0; } static int32_t a2dp_audio_sync_fix_diff_start(uint32_t tick) { TRACE_A2DP_DECODER_I("[SYNC] fix diff start"); a2dp_audio_sync_fix_diff.status = A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_START; a2dp_audio_sync_fix_diff.tick = tick; return 0; } static int a2dp_audio_sync_fix_diff_stop(uint32_t tick) { TRACE_A2DP_DECODER_I("[SYNC] fix diff stop"); a2dp_audio_sync_fix_diff.status = A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_STOP; a2dp_audio_sync_fix_diff.tick = 0; return 0; } static int32_t a2dp_audio_sync_fix_diff_reset(void) { TRACE_A2DP_DECODER_I("[SYNC] fix diff reset"); a2dp_audio_sync_fix_diff.status = A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_IDLE; a2dp_audio_sync_fix_diff.tick = 0; return 0; } static A2DP_AUDIO_SYNC_FIX_DIFF_STATUS a2dp_audio_sync_fix_diff_status_get(void) { return a2dp_audio_sync_fix_diff.status; } int a2dp_audio_sync_handler(uint8_t *buffer, uint32_t buffer_bytes) { A2DP_AUDIO_LASTFRAME_INFO_T *lastframe_info = NULL; A2DP_AUDIO_SYNC_T *audio_sync = &a2dp_audio_context.audio_sync; float diff_mtu = 0; bool need_tune = false; bool force_slow = false; #if defined(IBRT) if (!app_tws_ibrt_mobile_link_connected()){ return -1; } #endif if (a2dp_audio_internal_lastframe_info_ptr_get(&lastframe_info) < 0){ return -1; } a2dp_audio_sync_fix_diff_proc(audio_sync->tick); if (a2dp_audio_sync_fix_diff_status_get() == A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_STOP){ #if defined(IBRT) if (!app_tws_ibrt_audio_sync_tune_onprocess() && !a2dp_audio_sync_tune_onprocess() #else if (!a2dp_audio_sync_tune_onprocess() #endif ){ int sync_tune_result = 0; if (a2dp_audio_context.output_cfg.factor_reference != a2dp_audio_context.init_factor_reference){ sync_tune_result = a2dp_audio_sync_tune(a2dp_audio_context.init_factor_reference); } if (!sync_tune_result){ a2dp_audio_sync_fix_diff_reset(); #ifdef A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT TRACE_A2DP_DECODER_I("[SYNC] tune ratio normal %f mut:%5.3f->%d", (double)a2dp_audio_context.init_factor_reference, (double)a2dp_audio_context.average_packet_mut, a2dp_audio_context.dest_packet_mut); #else TRACE_A2DP_DECODER_I("[SYNC] tune ratio normal %d mut:%d->%d", (int32_t)(a2dp_audio_context.init_factor_reference * 10000000), (int32_t)(a2dp_audio_context.average_packet_mut+0.5f), a2dp_audio_context.dest_packet_mut); #endif }else{ TRACE_A2DP_DECODER_I("[SYNC] tune ratio normal busy"); } }else{ #ifdef A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT TRACE_A2DP_DECODER_I("[SYNC] tune ratio busy %f mut:%5.3f->%d", (double)a2dp_audio_context.init_factor_reference, (double)a2dp_audio_context.average_packet_mut, a2dp_audio_context.dest_packet_mut); #else TRACE_A2DP_DECODER_I("[SYNC] tune ratio busy %d mut:%d->%d", (int32_t)(a2dp_audio_context.init_factor_reference * 10000000), (int32_t)(a2dp_audio_context.average_packet_mut+0.5f), a2dp_audio_context.dest_packet_mut); #endif } goto exit; } if (audio_sync->tick%A2DP_AUDIO_SYNC_INTERVAL == 0){ diff_mtu = a2dp_audio_context.average_packet_mut-(float)a2dp_audio_context.dest_packet_mut; if (ABS(diff_mtu) < 0.6f){ #ifdef A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT TRACE_A2DP_DECODER_I("[SYNC] skip mut:%5.3f", (double)diff_mtu); #else TRACE_A2DP_DECODER_I("[SYNC] skip mut:0.%d", (int32_t)(diff_mtu*10)); #endif goto exit; }else if (diff_mtu/a2dp_audio_context.dest_packet_mut < -0.2f){ float curr_ratio = a2dp_audio_context.output_cfg.factor_reference; float ref_ratio = a2dp_audio_context.init_factor_reference; if (curr_ratio != (ref_ratio + A2DP_AUDIO_SYNC_FIX_DIFF_SLOW_LIMIT)){ #ifdef A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT TRACE_A2DP_DECODER_I("[SYNC] force slow mut:%5.3f", (double)diff_mtu); #else TRACE_A2DP_DECODER_I("[SYNC] force slow mut:0.%d", (int32_t)(diff_mtu*10)); #endif force_slow = true; } } if (a2dp_audio_sync_fix_diff_status_get() == A2DP_AUDIO_SYNC_FIX_DIFF_STATUS_IDLE || force_slow){ uint32_t dma_buffer_samples, samples, dma_interval; double ratio = 1.0, limit_ratio = 1.0; float sampleRate, ref_ratio, curr_ratio; float ref_us = 0; float dest_us = 0; float sample_us =0; dma_buffer_samples = app_bt_stream_get_dma_buffer_samples()/2; dma_interval = A2DP_AUDIO_SYNC_FIX_DIFF_INTERVAL; ref_ratio = a2dp_audio_context.init_factor_reference; curr_ratio = a2dp_audio_context.output_cfg.factor_reference; samples = dma_interval*dma_buffer_samples; sampleRate = lastframe_info->stream_info.sample_rate * ref_ratio; sample_us = 1e6 / sampleRate; ref_us = sample_us * (float)samples; dest_us = sample_us * (float)(lastframe_info->frame_samples * diff_mtu); ratio = ref_us/(ref_us - dest_us)*curr_ratio; if (ratio > (double)(ref_ratio + A2DP_AUDIO_SYNC_FIX_DIFF_FAST_LIMIT)){ limit_ratio = ref_ratio + A2DP_AUDIO_SYNC_FIX_DIFF_FAST_LIMIT; }else if (ratio < double(ref_ratio + A2DP_AUDIO_SYNC_FIX_DIFF_SLOW_LIMIT)){ limit_ratio = ref_ratio + A2DP_AUDIO_SYNC_FIX_DIFF_SLOW_LIMIT; }else{ limit_ratio = ratio; } TRACE_A2DP_DECODER_I("[SYNC] sampleRate:%d ref_ratio:%d samples:%d %d->%d", (int32_t)sampleRate, (int32_t)(ref_ratio * 10000000), samples, (int32_t)ref_us, (int32_t)dest_us); need_tune = true; #if defined(IBRT) if (!app_tws_ibrt_audio_sync_tune_onprocess() && !a2dp_audio_sync_tune_onprocess() && #else if (!a2dp_audio_sync_tune_onprocess() && #endif need_tune){ if (!a2dp_audio_sync_tune((float)limit_ratio)){ a2dp_audio_sync_fix_diff_start(dma_interval); #ifdef A2DP_AUDIO_SYNC_FIX_DIFF_INTERVA_PRINT_FLOAT TRACE_A2DP_DECODER_I("[SYNC] tune ratio %f mut:%5.3f->%d", limit_ratio, (double)a2dp_audio_context.average_packet_mut, a2dp_audio_context.dest_packet_mut); #else TRACE_A2DP_DECODER_I("[SYNC] tune ratio %d mut:%d->%d", (int32_t)(limit_ratio * 10000000), (int32_t)(a2dp_audio_context.average_packet_mut+0.5f), a2dp_audio_context.dest_packet_mut); #endif }else{ TRACE_A2DP_DECODER_I("[SYNC] tune ratio busy"); } } }else{ TRACE_A2DP_DECODER_I("[SYNC] avg_mut:%d dest_mtu:%d", (int32_t)(a2dp_audio_context.average_packet_mut+0.5f), a2dp_audio_context.dest_packet_mut); } }else{ } exit: audio_sync->tick++; return 0; } #else int a2dp_audio_sync_handler(uint8_t *buffer, uint32_t buffer_bytes) { A2DP_AUDIO_LASTFRAME_INFO_T *lastframe_info = NULL; A2DP_AUDIO_SYNC_T *audio_sync = &a2dp_audio_context.audio_sync; float dest_pid_result = .0f; float diff_mtu = 0; int32_t frame_mtu = 0; int32_t total_mtu = 0; float diff_factor = 0; #if defined(IBRT) if (!app_tws_ibrt_mobile_link_connected()){ return -1; } #endif if (a2dp_audio_internal_lastframe_info_ptr_get(&lastframe_info) < 0){ return -1; } if (audio_sync->tick++%A2DP_AUDIO_SYNC_INTERVAL == 0){ list_t *list = a2dp_audio_context.audio_datapath.input_raw_packet_list; A2DP_AUDIO_SYNC_PID_T *pid = &audio_sync->pid; //valid limter 0x80000 if (audio_sync->cnt < 0x80000){ audio_sync->cnt += A2DP_AUDIO_SYNC_INTERVAL; } frame_mtu = lastframe_info->stream_info.frame_samples/lastframe_info->frame_samples; total_mtu = audio_sync->cnt * frame_mtu; diff_mtu = a2dp_audio_context.average_packet_mut-(float)a2dp_audio_context.dest_packet_mut; #if 1 TRACE_A2DP_DECODER_I("[SYNC] sample:%d/%d diff:%d/%d/%d/%d curr:%d", lastframe_info->frame_samples, lastframe_info->stream_info.frame_samples, (int32_t)(diff_mtu+0.5f), (int32_t)(a2dp_audio_context.average_packet_mut+0.5f), a2dp_audio_context.dest_packet_mut, total_mtu, a2dp_audio_list_length(list) + get_in_cp_frame_cnt()); #else TRACE_A2DP_DECODER_I("[SYNC] diff:%10.9f/%10.9f frame_mut:%d dest:%d total:%d curr:%d", (double)diff_mtu, (double)a2dp_audio_context.average_packet_mut, frame_mtu, a2dp_audio_context.dest_packet_mut, total_mtu, a2dp_audio_list_length(list)); TRACE_A2DP_DECODER_I("[SYNC] try tune:%d, %10.9f %10.9f", diff_mtu != 0.f && audio_sync->tick != 1 ? ABS(diff_mtu) > ((float)frame_mtu * 0.2f): 0, (double)ABS(diff_mtu), (double)((float)frame_mtu * 0.2f)); #endif //TRACE(2,"audio_sync tune %d/%d tick", app_tws_ibrt_audio_sync_tune_onprocess(), a2dp_audio_sync_tune_onprocess(), audio_sync->tick); #if defined(IBRT) if ((!app_tws_ibrt_audio_sync_tune_onprocess() && !a2dp_audio_sync_tune_onprocess()) && #else if (!a2dp_audio_sync_tune_onprocess() && #endif diff_mtu != 0.f && audio_sync->tick != 1 && ((ABS(diff_mtu) > ((float)frame_mtu * 0.25f) && diff_mtu > 0)|| (ABS(diff_mtu) > ((float)frame_mtu * 0.1f) && diff_mtu < 0))){ diff_factor = diff_mtu/a2dp_audio_context.average_packet_mut; if (a2dp_audio_sync_pid_calc(pid, diff_factor)){ dest_pid_result = a2dp_audio_context.output_cfg.factor_reference + pid->result; if (dest_pid_result > (A2DP_AUDIO_SYNC_FACTOR_REFERENCE + A2DP_AUDIO_SYNC_FACTOR_FAST_LIMIT)){ dest_pid_result = A2DP_AUDIO_SYNC_FACTOR_REFERENCE + A2DP_AUDIO_SYNC_FACTOR_FAST_LIMIT; }else if (dest_pid_result < (A2DP_AUDIO_SYNC_FACTOR_REFERENCE + A2DP_AUDIO_SYNC_FACTOR_SLOW_LIMIT)){ dest_pid_result = A2DP_AUDIO_SYNC_FACTOR_REFERENCE + A2DP_AUDIO_SYNC_FACTOR_SLOW_LIMIT; } if (a2dp_audio_context.output_cfg.factor_reference != dest_pid_result){ if (!a2dp_audio_sync_tune(dest_pid_result)){ audio_sync->cnt = 0; } TRACE_A2DP_DECODER_I("[SYNC] tune diff_factor:%10.9f pid:%10.9f tune:%10.9f", (double)diff_factor, (double)pid->result, (double)dest_pid_result); }else{ TRACE_A2DP_DECODER_I("[SYNC] tune skip same"); } } }else{ /* TRACE_A2DP_DECODER_I("[SYNC] tune busy skip proc:%d/%d mtu:%d tick:%d >0:%d <0:%d tick:%d", app_tws_ibrt_audio_sync_tune_onprocess(), a2dp_audio_sync_tune_onprocess(), diff_mtu != 0.f, audio_sync->tick != 1, (ABS(diff_mtu) > ((float)frame_mtu * 0.25f) && diff_mtu > 0), (ABS(diff_mtu) > ((float)frame_mtu * 0.1f) && diff_mtu < 0), audio_sync->tick); */ } }else{ bool need_tune = false; if (lastframe_info->undecode_min_frames*10 <= a2dp_audio_context.dest_packet_mut*10/3){ dest_pid_result = a2dp_audio_context.init_factor_reference + A2DP_AUDIO_SYNC_FACTOR_NEED_FAST_CACHE; need_tune = true; }else if (lastframe_info->undecode_min_frames*10 <= a2dp_audio_context.dest_packet_mut*20/3){ dest_pid_result = a2dp_audio_context.init_factor_reference + A2DP_AUDIO_SYNC_FACTOR_SLOW_LIMIT; need_tune = true; } #if defined(IBRT) if (!app_tws_ibrt_audio_sync_tune_onprocess() && !a2dp_audio_sync_tune_onprocess() && #else if (!a2dp_audio_sync_tune_onprocess() && #endif need_tune){ if (a2dp_audio_context.output_cfg.factor_reference != dest_pid_result){ a2dp_audio_sync_reset_data(); a2dp_audio_sync_tune(dest_pid_result); TRACE_A2DP_DECODER_I("[SYNC] tune ratio force slow %d/%d->%d", lastframe_info->undecode_min_frames, lastframe_info->undecode_max_frames, a2dp_audio_context.dest_packet_mut); } } } return 0; } #endif #if A2DP_DECODER_HISTORY_SEQ_SAVE static int a2dp_audio_reset_history_seq(void) { a2dp_audio_status_mutex_lock(); for (uint8_t i=0; isequenceNumber - historySeqPre)!= 1){ TRACE_A2DP_DECODER_W("[INPUT] SEQ ERR %d/%d",historySeqPre, header->sequenceNumber); a2dp_audio_show_history_seq(); } } historySeq_idx = a2dp_audio_context.historySeq_idx%A2DP_DECODER_HISTORY_SEQ_SAVE; a2dp_audio_context.historySeq[historySeq_idx] = header->sequenceNumber; #ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE a2dp_audio_context.historyLoctime[historySeq_idx] = hal_fast_sys_timer_get(); #endif #ifdef A2DP_DECODER_HISTORY_CHECK_SUM_SAVE a2dp_audio_context.historyChecksum[historySeq_idx] = crc32(0, buf, len); #endif a2dp_audio_context.historySeq_idx++; a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_show_history_seq(void) { uint8_t i = 0, j = 1; uint16_t reordHistorySeq[A2DP_DECODER_HISTORY_SEQ_SAVE]; #ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE int32_t diff_max_idx = 0; int32_t diff_max_ms = 0; int64_t diff_avg_ms = 0; int32_t diff_avg_cnt = 0; uint32_t historyLoctime[A2DP_DECODER_HISTORY_SEQ_SAVE]; #endif #ifdef A2DP_DECODER_HISTORY_CHECK_SUM_SAVE uint32_t historyChecksum[A2DP_DECODER_HISTORY_SEQ_SAVE]; #endif a2dp_audio_status_mutex_lock(); for (i=0; i reordHistorySeq[j+1]) { uint16_t temp_seq = reordHistorySeq[j]; reordHistorySeq[j] = reordHistorySeq[j+1]; reordHistorySeq[j+1] = temp_seq; #ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE uint32_t temp_Loctime = historyLoctime[j]; historyLoctime[j] = historyLoctime[j+1]; historyLoctime[j+1] = temp_Loctime; #endif #ifdef A2DP_DECODER_HISTORY_CHECK_SUM_SAVE uint32_t temp_Checksum = historyChecksum[j]; historyChecksum[j] = historyChecksum[j+1]; historyChecksum[j+1] = temp_Checksum; #endif } } } #ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE for (i = 0, j = 1; i diff_max_ms){ diff_max_ms = tmp_ms; diff_max_idx = i; } if (tmp_ms > (int32_t)MS_TO_FAST_TICKS(50)){ TRACE_A2DP_DECODER_I("[INPUT] > 30ms seq:%d diff:%d :%d / %d", reordHistorySeq[i], FAST_TICKS_TO_MS(tmp_ms), historyLoctime[i], historyLoctime[j]); } } diff_avg_ms /= diff_avg_cnt; TRACE_A2DP_DECODER_I("[INPUT] max_diff:%dms idx:%d avg:%dus", FAST_TICKS_TO_MS(diff_max_ms), diff_max_idx, FAST_TICKS_TO_US(diff_avg_ms)); #endif // DUMP16("%d ", reordHistorySeq, A2DP_DECODER_HISTORY_SEQ_SAVE); #ifdef A2DP_DECODER_HISTORY_LOCTIME_SAVE DUMP32("%x ", historyLoctime, A2DP_DECODER_HISTORY_SEQ_SAVE); #endif #ifdef A2DP_DECODER_HISTORY_CHECK_SUM_SAVE DUMP32("%x ", historyChecksum, A2DP_DECODER_HISTORY_SEQ_SAVE); #endif a2dp_audio_status_mutex_unlock(); return 0; } #endif /* 1, 2^1 3, 2^2 7, 2^3 15, 2^4 31, 2^5 */ #define AUDIO_ALPHA_PRAMS_1 (3) #define AUDIO_ALPHA_PRAMS_2 (4) static inline float a2dp_audio_alpha_filter(float y, float x) { if (y){ y = ((AUDIO_ALPHA_PRAMS_1*y)+x)/AUDIO_ALPHA_PRAMS_2; }else{ y = x; } return y; } static void inline a2dp_audio_convert_16bit_to_24bit(int32_t *out, int16_t *in, int len) { for (int i = len - 1; i >= 0; i--) { out[i] = ((int32_t)in[i] << 8); } } static void inline a2dp_audio_channel_select(A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel, uint8_t *buffer, uint32_t buffer_bytes) { uint32_t samples; uint32_t i; ASSERT_A2DP_DECODER(a2dp_audio_context.output_cfg.num_channels == 2, "%s num_channels:%d", __func__, a2dp_audio_context.output_cfg.num_channels); if (a2dp_audio_context.output_cfg.bits_depth == 24){ int32_t *buf_l_p = (int32_t *)buffer; int32_t *buf_r_p = (int32_t *)buffer + 1; samples = buffer_bytes/4/2; switch (chnl_sel) { case A2DP_AUDIO_CHANNEL_SELECT_LRMERGE: for (i = 0; i>1; *buf_l_p = tmp_sample; *buf_r_p = tmp_sample; } break; case A2DP_AUDIO_CHANNEL_SELECT_LCHNL: for (i = 0; i>1; *buf_l_p = tmp_sample; *buf_r_p = tmp_sample; } break; case A2DP_AUDIO_CHANNEL_SELECT_LCHNL: for (i = 0; iframe_samples) ){ cp_frame_mtus = cp_frame_mtus /(info->frame_samples) +1; }else{ cp_frame_mtus = cp_frame_mtus /(info->frame_samples); } TRACE_A2DP_DECODER_I("[CP] cp_frame_mtus:%d", cp_frame_mtus); return cp_frame_mtus; } #else bool is_cp_need_reset(void) { return false; } #endif #define A2DP_AUDIO_SYSFREQ_BOOST_RESUME_CNT (20) uint32_t a2dp_audio_sysfreq_cnt = UINT32_MAX; uint32_t a2dp_audio_sysfreq_dest_boost_cnt = 0; APP_SYSFREQ_FREQ_T a2dp_audio_sysfreq_normalfreq = APP_SYSFREQ_52M; int a2dp_audio_sysfreq_boost_init(uint32_t normalfreq) { a2dp_audio_sysfreq_cnt = UINT32_MAX; a2dp_audio_sysfreq_dest_boost_cnt = 0; a2dp_audio_sysfreq_normalfreq = (APP_SYSFREQ_FREQ_T)normalfreq; TRACE_A2DP_DECODER_I("[BOOST] freq:%d", normalfreq); return 0; } int a2dp_audio_sysfreq_boost_start(uint32_t boost_cnt) { enum APP_SYSFREQ_FREQ_T sysfreq = APP_SYSFREQ_104M; a2dp_audio_sysfreq_cnt = 0; a2dp_audio_sysfreq_dest_boost_cnt = boost_cnt; if (a2dp_audio_sysfreq_normalfreq >= APP_SYSFREQ_52M){ sysfreq = APP_SYSFREQ_104M; }else{ sysfreq = APP_SYSFREQ_52M; } TRACE_A2DP_DECODER_I("[BOOST] freq:%d cnt:%d", sysfreq, boost_cnt); app_sysfreq_req(APP_SYSFREQ_USER_BT_A2DP, sysfreq); return 0; } static int a2dp_audio_sysfreq_boost_porc(void) { if (a2dp_audio_sysfreq_cnt == UINT32_MAX){ //do nothing }else if (a2dp_audio_sysfreq_cnt >= a2dp_audio_sysfreq_dest_boost_cnt){ a2dp_audio_sysfreq_cnt = UINT32_MAX; TRACE_A2DP_DECODER_I("[BOOST] freq:%d", a2dp_audio_sysfreq_normalfreq); app_sysfreq_req(APP_SYSFREQ_USER_BT_A2DP, a2dp_audio_sysfreq_normalfreq); }else{ a2dp_audio_sysfreq_cnt++; } return 0; } int a2dp_audio_sysfreq_boost_running(void) { return a2dp_audio_sysfreq_cnt == UINT32_MAX ? 0 : 1; } int a2dp_audio_store_packet_checker_start(void) { store_packet_history_loctime = 0; return 0; } int a2dp_audio_store_packet_checker(btif_media_header_t *header) { bool show_info = false; uint32_t fast_sys_tick = hal_fast_sys_timer_get(); int32_t tmp_ms = 0; if (store_packet_history_loctime){ tmp_ms = fast_sys_tick - store_packet_history_loctime; if (tmp_ms > (int32_t)MS_TO_FAST_TICKS(50)){ show_info = true; } } if (show_info){ //TRACE_A2DP_DECODER_I("[INPUT] >50ms seq:%d diff:%d", header->sequenceNumber, FAST_TICKS_TO_MS(tmp_ms)); a2dp_decoder_info_checker(); } store_packet_history_loctime = fast_sys_tick; if (a2dp_audio_context.historySeq_idx && ((a2dp_audio_context.historySeq_idx-1)%A2DP_DECODER_HISTORY_SEQ_SAVE == 0)){ a2dp_audio_show_history_seq(); } return 0; } //#define DECODER_ERR_TEST int a2dp_audio_store_packet(btif_media_header_t * header, unsigned char *buf, unsigned int len) { int nRet = A2DP_DECODER_NO_ERROR; if( a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_NULL) {//if mem deinit , drop data return nRet; } a2dp_audio_status_mutex_lock(); #ifdef DECODER_ERR_TEST static uint16_t cnt = 0; static uint16_t limit = 500; cnt++; if(cnt%limit==0){ cnt = 0; limit = rand()%500; uint16_t len2 = rand()%len; memset(buf+len-len2,0,len2); TRACE_A2DP_DECODER_I("[INPUT] Fill Err!!!! seq:%d", header->sequenceNumber); } #endif #if A2DP_DECODER_HISTORY_SEQ_SAVE a2dp_audio_save_history_seq(header, buf, len); #endif a2dp_audio_set_store_packet_status(A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_BUSY); if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_store_packet_checker(header); if (a2dp_audio_context.need_detect_first_packet){ a2dp_audio_context.need_detect_first_packet = false; a2dp_audio_context.audio_decoder.audio_decoder_preparse_packet(header, buf, len); } if (a2dp_audio_detect_next_packet_callback){ a2dp_audio_detect_next_packet_callback(header, buf, len); } nRet = a2dp_audio_context.audio_decoder.audio_decoder_store_packet(header, buf, len); #if defined(IBRT) if (is_cp_need_reset()){ TRACE_A2DP_DECODER_I("[CP] find cp error need restart"); app_ibrt_if_force_audio_retrigger(); } if (nRet == A2DP_DECODER_MTU_LIMTER_ERROR){ if (app_tws_ibrt_mobile_link_connected()){ // try again //a2dp_audio_semaphore_wait(A2DP_AUDIO_WAIT_TIMEOUT_MS); nRet = a2dp_audio_context.audio_decoder.audio_decoder_store_packet(header, buf, len); } if (nRet == A2DP_DECODER_MTU_LIMTER_ERROR){ int dest_discards_samples = 0; ibrt_ctrl_t *p_ibrt_ctrl = app_tws_ibrt_get_bt_ctrl_ctx(); if(p_ibrt_ctrl == NULL) { return A2DP_DECODER_NOT_SUPPORT; } if (app_tws_ibrt_mobile_link_connected()){ bt_syn_trig_checker(p_ibrt_ctrl->mobile_conhandle); }else if (app_tws_ibrt_slave_ibrt_link_connected()){ bt_syn_trig_checker(p_ibrt_ctrl->ibrt_conhandle); } dest_discards_samples = app_bt_stream_get_dma_buffer_samples()/2; a2dp_audio_discards_samples(dest_discards_samples*2); a2dp_audio_context.audio_decoder.audio_decoder_store_packet(header, buf, len); TRACE_A2DP_DECODER_I("[INPUT] MTU_LIMTER so discards_packet"); } } #else if (is_cp_need_reset()){ TRACE_A2DP_DECODER_I("[CP] find cp error need restart"); app_audio_decode_err_force_trigger(); } if (nRet == A2DP_DECODER_MTU_LIMTER_ERROR){ a2dp_audio_synchronize_dest_packet_mut(a2dp_audio_context.dest_packet_mut); a2dp_audio_context.audio_decoder.audio_decoder_store_packet(header, buf, len); TRACE_A2DP_DECODER_W("[INPUT] MTU_LIMTER so discards_packet"); } #endif }else{ TRACE(2,"[INPUT] skip packet status:%d", a2dp_audio_get_status()); } if (a2dp_audio_store_packet_callback){ a2dp_audio_store_packet_callback(header, buf, len); } a2dp_audio_set_store_packet_status(A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_IDLE); a2dp_audio_status_mutex_unlock(); return 0; } uint32_t a2dp_audio_playback_handler(uint8_t *buffer, uint32_t buffer_bytes) { uint32_t len = buffer_bytes; int nRet = A2DP_DECODER_NO_ERROR; A2DP_AUDIO_LASTFRAME_INFO_T *lastframe_info = NULL; list_t *list = a2dp_audio_context.audio_datapath.input_raw_packet_list; a2dp_audio_set_playback_status(A2DP_AUDIO_DECODER_PLAYBACK_STATUS_BUSY); if (a2dp_audio_get_status() != A2DP_AUDIO_DECODER_STATUS_START){ TRACE_A2DP_DECODER_W("[PLAYBACK] skip handler status:%d", a2dp_audio_get_status()); goto exit; } a2dp_audio_sysfreq_boost_porc(); if (a2dp_audio_context.average_packet_mut == 0){ A2DP_AUDIO_HEADFRAME_INFO_T headframe_info; a2dp_audio_decoder_headframe_info_get(&headframe_info); a2dp_audio_context.average_packet_mut = a2dp_audio_list_length(list); TRACE_A2DP_DECODER_I("[PLAYBACK] init average_packet_mut:%d seq:%d", (uint16_t)(a2dp_audio_context.average_packet_mut+0.5f), headframe_info.sequenceNumber); }else{ if (!a2dp_audio_refill_packet()){ uint16_t packet_mut = 0; if (!a2dp_audio_internal_lastframe_info_ptr_get(&lastframe_info)){ packet_mut = a2dp_audio_list_length(list) + get_in_cp_frame_cnt() + get_in_cp_frame_delay() * (lastframe_info->frame_samples /lastframe_info->list_samples); a2dp_audio_context.average_packet_mut = a2dp_audio_alpha_filter((float)a2dp_audio_context.average_packet_mut, (float)packet_mut); a2dp_audio_sync_handler(buffer, buffer_bytes); } } } #if defined(A2DP_AUDIO_REFILL_AFTER_NO_CACHE) if (a2dp_audio_context.skip_frame_cnt_after_no_cache){ #if defined(A2DP_CP_ACCEL) uint32_t cp_delay_mtus = get_in_cp_frame_delay(); cp_delay_mtus *= get_cp_frame_mtus(&a2dp_audio_lastframe_info); if (a2dp_audio_list_length(list) >= (a2dp_audio_context.dest_packet_mut - cp_delay_mtus)){ a2dp_audio_context.skip_frame_cnt_after_no_cache = 0; } #else if (a2dp_audio_list_length(list) >= a2dp_audio_context.dest_packet_mut){ a2dp_audio_context.skip_frame_cnt_after_no_cache = 0; } #endif memset(buffer, 0, buffer_bytes); TRACE_A2DP_DECODER_I("[PLAYBACK] decode refill skip_cnt:%d, list:%d", a2dp_audio_context.skip_frame_cnt_after_no_cache, a2dp_audio_list_length(list)); a2dp_decoder_info_checker(); if (a2dp_audio_context.skip_frame_cnt_after_no_cache > 0){ a2dp_audio_context.skip_frame_cnt_after_no_cache--; }else{ a2dp_audio_context.mute_frame_cnt_after_no_cache = A2DP_AUDIO_MUTE_FRAME_CNT_AFTER_NO_CACHE; } }else #endif { if (a2dp_audio_context.output_cfg.bits_depth == 24 && 16 == bt_sbc_player_get_sample_bit()){ len = len / (sizeof(int32_t) / sizeof(int16_t)); nRet = a2dp_audio_context.audio_decoder.audio_decoder_decode_frame(buffer, len); if (nRet < 0 || a2dp_audio_context.mute_frame_cnt_after_no_cache){ TRACE_A2DP_DECODER_I("[PLAYBACK] decode failed nRet=%d mute_cnt:%d", nRet, a2dp_audio_context.mute_frame_cnt_after_no_cache); a2dp_decoder_info_checker(); //mute frame memset(buffer, 0, len); } a2dp_audio_convert_16bit_to_24bit((int32_t *)buffer, (int16_t *)buffer, len / sizeof(int16_t)); // Restore len to 24-bit sample buffer length len = len * (sizeof(int32_t) / sizeof(int16_t)); }else if (a2dp_audio_context.output_cfg.bits_depth == a2dp_audio_context.audio_decoder.stream_info.bits_depth){ nRet = a2dp_audio_context.audio_decoder.audio_decoder_decode_frame(buffer, len); if (nRet < 0 || a2dp_audio_context.mute_frame_cnt_after_no_cache){ //mute frame TRACE_A2DP_DECODER_I("[PLAYBACK] decode failed nRet=%d mute_cnt:%d", nRet, a2dp_audio_context.mute_frame_cnt_after_no_cache); a2dp_decoder_info_checker(); memset(buffer, 0, len); } } a2dp_audio_channel_select(a2dp_audio_context.chnl_sel, buffer, buffer_bytes); } a2dp_audio_semaphore_release(); if (nRet == A2DP_DECODER_CACHE_UNDERFLOW_ERROR) { if (a2dp_audio_internal_lastframe_info_ptr_get(&lastframe_info) < 0) { goto exit; } TRACE(2,"CACHE_UNDERFLOW lastseq:%d ftick:%d", lastframe_info->sequenceNumber, hal_fast_sys_timer_get()); a2dp_audio_show_history_seq(); uint32_t mute_frames = A2DP_AUDIO_MUTE_FRAME_CNT_AFTER_NO_CACHE; uint32_t skip_frames = A2DP_AUDIO_SKIP_FRAME_LIMIT_AFTER_NO_CACHE - get_in_cp_frame_delay(); a2dp_audio_context.mute_frame_cnt_after_no_cache = (uint32_t)((float)mute_frames * a2dp_audio_latency_factor_get()); a2dp_audio_context.skip_frame_cnt_after_no_cache = (uint32_t)((float)skip_frames * a2dp_audio_latency_factor_get()); a2dp_audio_context.average_packet_mut = 0; a2dp_audio_sync_reset_data(); #if defined(IBRT) a2dp_audio_sync_tune_sample_rate(app_tws_ibrt_audio_sync_config_factor_reference_get()); #else a2dp_audio_sync_tune_sample_rate(a2dp_audio_context.init_factor_reference); #endif a2dp_decoder_info_checker(); }else{ if (a2dp_audio_context.mute_frame_cnt_after_no_cache > 0){ a2dp_audio_context.mute_frame_cnt_after_no_cache--; a2dp_audio_context.average_packet_mut = 0; if (a2dp_audio_context.mute_frame_cnt_after_no_cache >= 1){ a2dp_audio_synchronize_dest_packet_mut(a2dp_audio_context.dest_packet_mut); } } } if (!a2dp_audio_internal_lastframe_info_ptr_get(&lastframe_info)){ lastframe_info->stream_info.factor_reference = a2dp_audio_context.output_cfg.factor_reference; lastframe_info->average_frames = (uint32_t)(a2dp_audio_context.average_packet_mut + 0.5f); } exit: a2dp_audio_set_playback_status(A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE); #if defined(IBRT) if (nRet == A2DP_DECODER_CACHE_UNDERFLOW_ERROR){ #if defined(A2DP_AUDIO_UNDERFLOW_CAUSE_AUDIO_RETRIGGER) bool force_audio_retrigger = true; #else bool force_audio_retrigger = false; #endif if (a2dp_audio_latency_factor_get() == A2DP_AUDIO_LATENCY_LOW_FACTOR && app_tws_ibrt_mobile_link_connected()){ a2dp_audio_latency_factor_sethigh(); if (app_tws_ibrt_tws_link_connected() && app_ibrt_ui_is_profile_exchanged()){ float latency_factor = a2dp_audio_latency_factor_get(); tws_ctrl_send_cmd(APP_TWS_CMD_SET_LATENCYFACTOR, (uint8_t*)&latency_factor, sizeof(latency_factor)); force_audio_retrigger = true; } } if (force_audio_retrigger && !a2dp_audio_context.underflow_onporcess){ a2dp_audio_context.underflow_onporcess = true; app_ibrt_if_force_audio_retrigger(); } } #else if (nRet == A2DP_DECODER_CACHE_UNDERFLOW_ERROR){ app_audio_decode_err_force_trigger(); } #endif return len; } static void a2dp_audio_packet_free(void *packet) { if (a2dp_audio_context.audio_decoder.audio_decoder_packet_free){ a2dp_audio_context.audio_decoder.audio_decoder_packet_free(packet); }else{ a2dp_audio_heap_free(packet); } } void a2dp_audio_clear_input_raw_packet_list(void) { //just clean the packet list to start receive ai data again if(a2dp_audio_context.audio_datapath.input_raw_packet_list) a2dp_audio_list_clear(a2dp_audio_context.audio_datapath.input_raw_packet_list); } int a2dp_audio_init(uint32_t sysfreq, A2DP_AUDIO_CODEC_TYPE codec_type, A2DP_AUDIO_OUTPUT_CONFIG_T *config, A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel, uint16_t dest_packet_mut) { uint8_t *heap_buff = NULL; uint32_t heap_size = 0; double ratio = 0; A2DP_AUDIO_OUTPUT_CONFIG_T decoder_output_config; TRACE_A2DP_DECODER_I("[INIT] freq:%d codec:%d chnl:%d", sysfreq, codec_type, chnl_sel); TRACE_A2DP_DECODER_I("[INIT] out:%d-%d-%d smp:%d dest:%d", config->sample_rate, config->num_channels, config->bits_depth, config->frame_samples, dest_packet_mut); a2dp_audio_sysfreq_boost_init(sysfreq); a2dp_audio_sysfreq_boost_start(A2DP_AUDIO_SYSFREQ_BOOST_RESUME_CNT); a2dp_audio_semaphore_init(); a2dp_audio_buffer_mutex_init(); a2dp_audio_status_mutex_init(); a2dp_audio_status_mutex_lock(); a2dp_audio_detect_next_packet_callback_register(NULL); a2dp_audio_detect_store_packet_callback_register(NULL); #if defined(A2DP_LDAC_ON) if(bt_sbc_player_get_codec_type()==BTIF_AVDTP_CODEC_TYPE_NON_A2DP) { heap_size = A2DP_AUDIO_LDAC_MEMPOOL_SIZE; } else #endif { heap_size = A2DP_AUDIO_MEMPOOL_SIZE; } app_audio_mempool_get_buff(&heap_buff, heap_size); ASSERT_A2DP_DECODER(heap_buff, "%s size:%d", __func__, heap_size); a2dp_audio_heap_init(heap_buff, heap_size); memset(&a2dp_audio_lastframe_info, 0, sizeof(A2DP_AUDIO_LASTFRAME_INFO_T)); a2dp_audio_context.audio_datapath.input_raw_packet_list = a2dp_audio_list_new(a2dp_audio_packet_free, (list_mempool_zmalloc)a2dp_audio_heap_cmalloc, (list_mempool_free)a2dp_audio_heap_free); a2dp_audio_context.audio_datapath.output_pcm_packet_list = a2dp_audio_list_new(a2dp_audio_packet_free, (list_mempool_zmalloc)a2dp_audio_heap_cmalloc, (list_mempool_free)a2dp_audio_heap_free); memcpy(&(a2dp_audio_context.output_cfg), config, sizeof(A2DP_AUDIO_OUTPUT_CONFIG_T)); ratio = a2dp_audio_context.output_cfg.factor_reference; a2dp_audio_context.output_cfg.factor_reference = 0; a2dp_audio_context.init_factor_reference = config->factor_reference; a2dp_audio_context.chnl_sel = chnl_sel; a2dp_audio_context.dest_packet_mut = dest_packet_mut; a2dp_audio_context.average_packet_mut = 0; switch (codec_type) { case A2DP_AUDIO_CODEC_TYPE_SBC: decoder_output_config.sample_rate = config->sample_rate; decoder_output_config.num_channels = 2; decoder_output_config.bits_depth = 16; decoder_output_config.frame_samples = config->frame_samples; decoder_output_config.factor_reference = 1.0f; memcpy(&(a2dp_audio_context.audio_decoder), &a2dp_audio_sbc_decoder_config, sizeof(A2DP_AUDIO_DECODER_T)); break; #if defined(A2DP_AAC_ON) case A2DP_AUDIO_CODEC_TYPE_MPEG2_4_AAC: decoder_output_config.sample_rate = config->sample_rate; decoder_output_config.num_channels = 2; decoder_output_config.bits_depth = 16; decoder_output_config.frame_samples = config->frame_samples; decoder_output_config.factor_reference = 1.0f; memcpy(&(a2dp_audio_context.audio_decoder), &a2dp_audio_aac_lc_decoder_config, sizeof(A2DP_AUDIO_DECODER_T)); break; #endif #if defined(A2DP_SCALABLE_ON) case A2DP_AUDIO_CODEC_TYPE_SCALABL: decoder_output_config.sample_rate = config->sample_rate; decoder_output_config.num_channels = 2; decoder_output_config.bits_depth = config->curr_bits; decoder_output_config.frame_samples = config->frame_samples; decoder_output_config.factor_reference = 1.0f; memcpy(&(a2dp_audio_context.audio_decoder), &a2dp_audio_scalable_decoder_config, sizeof(A2DP_AUDIO_DECODER_T)); break; #endif #if defined(A2DP_LHDC_ON) case A2DP_AUDIO_CODEC_TYPE_LHDC: decoder_output_config.sample_rate = config->sample_rate; decoder_output_config.num_channels = 2; decoder_output_config.bits_depth = config->curr_bits; decoder_output_config.frame_samples = config->frame_samples; decoder_output_config.factor_reference = 1.0f; memcpy(&(a2dp_audio_context.audio_decoder), &a2dp_audio_lhdc_decoder_config, sizeof(A2DP_AUDIO_DECODER_T)); break; #endif #if defined(A2DP_LDAC_ON) case A2DP_AUDIO_CODEC_TYPE_LDAC: decoder_output_config.sample_rate = config->sample_rate; decoder_output_config.num_channels = 2; decoder_output_config.bits_depth = config->curr_bits; decoder_output_config.frame_samples = config->frame_samples; decoder_output_config.factor_reference = 1.0f; memcpy(&(a2dp_audio_context.audio_decoder), &a2dp_audio_ldac_decoder_config, sizeof(A2DP_AUDIO_DECODER_T)); break; #endif default: ASSERT_A2DP_DECODER(0, "%s invalid codec_type:%d", __func__, codec_type); break; } a2dp_audio_context.audio_decoder.audio_decoder_init(&decoder_output_config, (void *)&a2dp_audio_context); a2dp_audio_context.need_detect_first_packet = true; a2dp_audio_context.underflow_onporcess = false; a2dp_audio_context.skip_frame_cnt_after_no_cache = 0; a2dp_audio_context.mute_frame_cnt_after_no_cache = 0; a2dp_audio_context.audio_decoder_status = A2DP_AUDIO_DECODER_STATUS_READY; a2dp_audio_context.store_packet_status = A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_IDLE; a2dp_audio_context.playback_status = A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE; a2dp_audio_sync_init(ratio); #if A2DP_DECODER_HISTORY_SEQ_SAVE a2dp_audio_reset_history_seq(); #endif a2dp_audio_store_packet_checker_start(); a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_deinit(void) { TRACE_A2DP_DECODER_I("[DEINIT]"); a2dp_audio_status_mutex_lock(); a2dp_audio_detect_next_packet_callback_register(NULL); a2dp_audio_detect_store_packet_callback_register(NULL); a2dp_audio_context.audio_decoder.audio_decoder_deinit(); memset(&(a2dp_audio_context.audio_decoder), 0, sizeof(A2DP_AUDIO_DECODER_T)); memset(&(a2dp_audio_context.output_cfg), 0, sizeof(A2DP_AUDIO_OUTPUT_CONFIG_T)); a2dp_audio_list_clear(a2dp_audio_context.audio_datapath.input_raw_packet_list); a2dp_audio_list_free(a2dp_audio_context.audio_datapath.input_raw_packet_list); a2dp_audio_context.audio_datapath.input_raw_packet_list = NULL; a2dp_audio_list_clear(a2dp_audio_context.audio_datapath.output_pcm_packet_list); a2dp_audio_list_free(a2dp_audio_context.audio_datapath.output_pcm_packet_list); a2dp_audio_context.audio_datapath.output_pcm_packet_list = NULL; size_t total = 0, used = 0, max_used = 0; a2dp_audio_heap_info(&total, &used, &max_used); TRACE_A2DP_DECODER_I("[DEINIT] heap info: total - %d, used - %d, max_used - %d.", total, used, max_used); //ASSERT_A2DP_DECODER(used == 0, "[%s] used != 0", __func__); a2dp_audio_set_store_packet_status(A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_IDLE); a2dp_audio_set_playback_status(A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE); a2dp_audio_set_status(A2DP_AUDIO_DECODER_STATUS_NULL); #if A2DP_DECODER_HISTORY_SEQ_SAVE a2dp_audio_reset_history_seq(); #endif a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_stop(void) { TRACE_A2DP_DECODER_I("[STOP]"); int cnt = 0; a2dp_audio_set_status(A2DP_AUDIO_DECODER_STATUS_STOP); a2dp_audio_semaphore_release(); cnt = 50; do { if (a2dp_audio_get_playback_status() == A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE){ TRACE_A2DP_DECODER_I("[DEINIT]PLAYBACK_STATUS_IDLE cnt:%d", cnt); break; }else{ osThreadYield(); } }while(--cnt > 0); cnt = 50; do { if (a2dp_audio_get_store_packet_status() == A2DP_AUDIO_DECODER_STORE_PACKET_STATUS_IDLE){ TRACE_A2DP_DECODER_I("[DEINIT] STORE_PACKET_STATUS_IDLE cnt:%d", cnt); break; }else{ osThreadYield(); } }while(--cnt > 0); return 0; } int a2dp_audio_start(void) { TRACE_A2DP_DECODER_I("[START]"); a2dp_audio_status_mutex_lock(); a2dp_audio_set_status(A2DP_AUDIO_DECODER_STATUS_START); a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_detect_next_packet_callback_register(A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK callback) { a2dp_audio_status_mutex_lock(); a2dp_audio_detect_next_packet_callback = callback; a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_detect_store_packet_callback_register(A2DP_AUDIO_DETECT_NEXT_PACKET_CALLBACK callback) { a2dp_audio_status_mutex_lock(); a2dp_audio_store_packet_callback = callback; a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_detect_first_packet(void) { a2dp_audio_status_mutex_lock(); a2dp_audio_context.need_detect_first_packet = true; a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_detect_first_packet_clear(void) { a2dp_audio_status_mutex_lock(); a2dp_audio_context.need_detect_first_packet = false; a2dp_audio_status_mutex_unlock(); return 0; } int a2dp_audio_discards_packet(uint32_t packets) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_status_mutex_lock(); nRet = a2dp_audio_context.audio_decoder.audio_decoder_discards_packet(packets); a2dp_audio_status_mutex_unlock(); }else{ nRet = -1; } return nRet; } int a2dp_audio_synchronize_dest_packet_mut(uint32_t mtu) { int nRet = 0; int cnt = 50; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ do { if (a2dp_audio_get_playback_status() == A2DP_AUDIO_DECODER_PLAYBACK_STATUS_IDLE){ nRet = a2dp_audio_context.audio_decoder.audio_decoder_synchronize_dest_packet_mut(mtu); break; }else{ osThreadYield(); } }while(--cnt > 0); }else{ nRet = -1; } return nRet; } int a2dp_audio_discards_samples(uint32_t samples) { return a2dp_audio_context.audio_decoder.a2dp_audio_discards_samples(samples); } int a2dp_audio_convert_list_to_samples(uint32_t *samples) { return a2dp_audio_context.audio_decoder.a2dp_audio_convert_list_to_samples(samples); } int a2dp_audio_get_packet_samples(void) { A2DP_AUDIO_LASTFRAME_INFO_T lastframe_info; uint32_t packet_samples = 0; uint16_t totalSubSequenceNumber = 1; a2dp_audio_lastframe_info_get(&lastframe_info); if (lastframe_info.totalSubSequenceNumber){ totalSubSequenceNumber = lastframe_info.totalSubSequenceNumber; } packet_samples = totalSubSequenceNumber * lastframe_info.frame_samples; return packet_samples; } static int a2dp_audio_internal_lastframe_info_ptr_get(A2DP_AUDIO_LASTFRAME_INFO_T **lastframe_info) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ *lastframe_info = &a2dp_audio_lastframe_info; }else{ *lastframe_info = NULL; nRet = -1; } return nRet; } int a2dp_audio_lastframe_info_get(A2DP_AUDIO_LASTFRAME_INFO_T *lastframe_info) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_buffer_mutex_lock(); memcpy(lastframe_info, &a2dp_audio_lastframe_info, sizeof(A2DP_AUDIO_LASTFRAME_INFO_T)); a2dp_audio_buffer_mutex_unlock(); }else{ memset(lastframe_info, 0, sizeof(A2DP_AUDIO_LASTFRAME_INFO_T)); nRet = -1; } return nRet; } int a2dp_audio_decoder_internal_check_sum_reset(void) { check_sum_seed = 0; return 0; } uint32_t a2dp_audio_decoder_internal_check_sum_generate(const uint8_t *buf, uint32_t len) { #if A2DP_DECODER_CHECKER check_sum_seed = crc32(check_sum_seed, buf, len); #else check_sum_seed = 0; #endif return check_sum_seed; } int a2dp_audio_lastframe_info_reset_undecodeframe(void) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_buffer_mutex_lock(); a2dp_audio_lastframe_info.undecode_frames = 0; a2dp_audio_lastframe_info.undecode_max_frames = 0; a2dp_audio_lastframe_info.undecode_min_frames = 0xffff; a2dp_audio_decoder_internal_check_sum_reset(); a2dp_audio_lastframe_info.check_sum = 0; a2dp_audio_buffer_mutex_unlock(); }else{ nRet = -1; } return nRet; } int a2dp_audio_decoder_internal_lastframe_info_set(A2DP_AUDIO_DECODER_LASTFRAME_INFO_T *lastframe_info) { a2dp_audio_buffer_mutex_lock(); a2dp_audio_lastframe_info.sequenceNumber = lastframe_info->sequenceNumber; a2dp_audio_lastframe_info.timestamp = lastframe_info->timestamp; a2dp_audio_lastframe_info.curSubSequenceNumber = lastframe_info->curSubSequenceNumber; a2dp_audio_lastframe_info.totalSubSequenceNumber= lastframe_info->totalSubSequenceNumber; a2dp_audio_lastframe_info.frame_samples = lastframe_info->frame_samples; a2dp_audio_lastframe_info.list_samples = lastframe_info->list_samples; a2dp_audio_lastframe_info.decoded_frames = lastframe_info->decoded_frames; a2dp_audio_lastframe_info.undecode_frames = lastframe_info->undecode_frames; a2dp_audio_lastframe_info.undecode_max_frames = MAX(a2dp_audio_lastframe_info.undecode_frames, a2dp_audio_lastframe_info.undecode_max_frames); a2dp_audio_lastframe_info.undecode_min_frames = MIN(a2dp_audio_lastframe_info.undecode_frames, a2dp_audio_lastframe_info.undecode_min_frames); a2dp_audio_lastframe_info.stream_info = lastframe_info->stream_info; a2dp_audio_lastframe_info.check_sum = lastframe_info->check_sum; a2dp_audio_buffer_mutex_unlock(); return 0; } int a2dp_audio_synchronize_packet(A2DP_AUDIO_SYNCFRAME_INFO_T *sync_info, uint32_t mask) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_status_mutex_lock(); nRet = a2dp_audio_context.audio_decoder.audio_decoder_synchronize_packet(sync_info, mask); if (nRet == A2DP_DECODER_NOT_SUPPORT){ //can't support synchronize packet, so return fake val; nRet = A2DP_DECODER_NO_ERROR; } a2dp_audio_status_mutex_unlock(); }else{ nRet = -1; } return nRet; } int a2dp_audio_decoder_headframe_info_get(A2DP_AUDIO_HEADFRAME_INFO_T *headframe_info) { int nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ nRet = a2dp_audio_context.audio_decoder.audio_decoder_headframe_info_get(headframe_info); }else{ memset(headframe_info, 0, sizeof(A2DP_AUDIO_HEADFRAME_INFO_T)); nRet = -1; } return nRet; } int a2dp_audio_refill_packet(void) { int refill_cnt = 0; #if defined(A2DP_AUDIO_REFILL_AFTER_NO_CACHE) refill_cnt += a2dp_audio_context.skip_frame_cnt_after_no_cache; #endif refill_cnt += a2dp_audio_context.mute_frame_cnt_after_no_cache; return refill_cnt; } bool a2dp_audio_auto_synchronize_support(void) { bool nRet = 0; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_buffer_mutex_lock(); nRet = a2dp_audio_context.audio_decoder.auto_synchronize_support > 0 ? true: false; a2dp_audio_buffer_mutex_unlock(); }else{ nRet = 0; } return nRet; } A2DP_AUDIO_OUTPUT_CONFIG_T *a2dp_audio_get_output_config(void) { A2DP_AUDIO_OUTPUT_CONFIG_T *output_config = NULL; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_buffer_mutex_lock(); output_config = &a2dp_audio_context.output_cfg; a2dp_audio_buffer_mutex_unlock(); }else{ output_config = NULL; } return output_config; } int a2dp_audio_latency_factor_setlow(void) { a2dp_audio_latency_factor = A2DP_AUDIO_LATENCY_LOW_FACTOR; return 0; } int a2dp_audio_latency_factor_sethigh(void) { a2dp_audio_latency_factor = A2DP_AUDIO_LATENCY_HIGH_FACTOR; return 0; } float a2dp_audio_latency_factor_get(void) { return a2dp_audio_latency_factor; } int a2dp_audio_latency_factor_set(float factor) { a2dp_audio_latency_factor = factor; return 0; } int a2dp_audio_latency_factor_status_get(A2DP_AUDIO_LATENCY_STATUS_E *latency_status, float *more_latency_factor) { if (a2dp_audio_latency_factor == A2DP_AUDIO_LATENCY_HIGH_FACTOR){ *latency_status = A2DP_AUDIO_LATENCY_STATUS_HIGH; *more_latency_factor = A2DP_AUDIO_LATENCY_MORE_FACTOR; }else{ *latency_status = A2DP_AUDIO_LATENCY_STATUS_LOW; *more_latency_factor = 1.0f; } return 0; } int a2dp_audio_frame_delay_get(void) { return get_in_cp_frame_delay(); } int a2dp_audio_dest_packet_mut_get(void) { return a2dp_audio_context.dest_packet_mut; } int a2dp_audio_set_channel_select(A2DP_AUDIO_CHANNEL_SELECT_E chnl_sel) { int nRet = A2DP_DECODER_NO_ERROR; if (a2dp_audio_get_status() == A2DP_AUDIO_DECODER_STATUS_START){ a2dp_audio_context.chnl_sel = chnl_sel; if (a2dp_audio_context.audio_decoder.audio_decoder_channel_select) { nRet = a2dp_audio_context.audio_decoder.audio_decoder_channel_select(chnl_sel); } } return nRet; } float a2dp_audio_get_sample_reference(void) { TRACE(1,"a2dp_audio_get_sample_reference:%d", (int32_t)(a2dp_audio_context.output_cfg.factor_reference * 10000000)); return a2dp_audio_context.output_cfg.factor_reference; } int8_t a2dp_audio_get_current_buf_size(void) { TRACE(1,"a2dp_audio_get_current_buf_size:%d",(int8_t)(a2dp_audio_context.average_packet_mut+0.5f)); return (int8_t)(a2dp_audio_context.average_packet_mut+0.5f); }