/*************************************************************************** * * Copyright 2015-2019 BES. * All rights reserved. All unpublished rights reserved. * * No part of this work may be used or reproduced in any form or by any * means, or stored in a database or retrieval system, without prior written * permission of BES. * * Use of this work is governed by a license granted by BES. * This work contains confidential and proprietary information of * BES. which is protected by copyright, trade secret, * trademark and other intellectual property rights. * ****************************************************************************/ #include "usb_audio_app.h" #include "analog.h" #include "audio_resample_ex.h" #include "audioflinger.h" #include "cmsis.h" #include "hal_aud.h" #include "hal_codec.h" #include "hal_location.h" #include "hal_sleep.h" #include "hal_sysfreq.h" #include "hal_timer.h" #include "hal_trace.h" #include "memutils.h" #include "pmu.h" #include "resample_coef.h" #include "safe_queue.h" #include "string.h" #include "tgt_hardware.h" #include "usb_audio.h" #include "usb_audio_frm_defs.h" #include "usb_audio_sync.h" #ifdef _VENDOR_MSG_SUPPT_ #include "usb_vendor_msg.h" #endif #if defined(USB_AUDIO_SPEECH) #include "app_overlay.h" #include "speech_process.h" #endif #if defined(__HW_FIR_DSD_PROCESS__) #include "dsd_process.h" #endif #if defined(AUDIO_ANC_FB_MC) #include "anc_process.h" #endif #include "hw_codec_iir_process.h" #include "hw_iir_process.h" #ifdef __AUDIO_RESAMPLE__ #ifdef SW_PLAYBACK_RESAMPLE #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) #error "Software playback resample conflicts with ANC/AuxMic" #endif #else #ifdef CHIP_BEST1000 #error "No hardware playback resample support" #endif #endif #ifndef SW_CAPTURE_RESAMPLE #if defined(CHIP_BEST1000) || defined(CHIP_BEST2000) #error "No hardware capture resample support" #endif #endif #endif // __AUDIO_RESAMPLE__ #ifdef CODEC_DSD #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_IIR_EQ_PROCESS__) || defined(__HW_DAC_IIR_EQ_PROCESS__) #error "EQ conflicts with CODEC_DSD" #endif #ifdef FREQ_RESP_EQ #error "FREQ_RESP_EQ conflicts with CODEC_DSD" #endif #ifdef __HW_FIR_DSD_PROCESS__ #error "__HW_FIR_DSD_PROCESS__ conflicts with CODEC_DSD" #endif #ifdef AUDIO_ANC_FB_MC #error "AUDIO_ANC_FB_MC conflicts with CODEC_DSD" #endif #ifdef NOISE_GATING #error "NOISE_GATING conflicts with CODEC_DSD" #endif #ifdef NOISE_REDUCTION #error "NOISE_REDUCTION conflicts with CODEC_DSD" #endif #endif #if defined(__SW_IIR_EQ_PROCESS__) static uint8_t audio_eq_sw_iir_index = 0; extern const IIR_CFG_T *const audio_eq_sw_iir_cfg_list[]; #endif #if defined(__HW_FIR_EQ_PROCESS__) static uint8_t audio_eq_hw_fir_index = 0; extern const FIR_CFG_T *const audio_eq_hw_fir_cfg_list[]; #endif #if defined(__HW_DAC_IIR_EQ_PROCESS__) static uint8_t audio_eq_hw_dac_iir_index = 0; extern const IIR_CFG_T *const audio_eq_hw_dac_iir_cfg_list[]; #endif #if defined(__HW_IIR_EQ_PROCESS__) static uint8_t audio_eq_hw_iir_index = 0; extern const IIR_CFG_T *const audio_eq_hw_iir_cfg_list[]; #endif #define KEY_TRACE //#define UNMUTE_WHEN_SET_VOL #define STREAM_RATE_BITS_SETUP #if defined(USB_AUDIO_DYN_CFG) && defined(ANC_L_R_MISALIGN_WORKAROUND) #ifndef AUDIO_PLAYBACK_24BIT //#define AUDIO_PLAYBACK_24BIT #endif #endif #if defined(__HW_FIR_DSD_PROCESS__) || defined(CODEC_DSD) #define DSD_SUPPORT #endif #ifdef TARGET_TO_MAX_DIFF #if defined(USB_AUDIO_RECV_ENABLE) && defined(USB_AUDIO_SEND_ENABLE) #if defined(__AUDIO_RESAMPLE__) && defined(PLL_TUNE_SAMPLE_RATE) #define UAUD_SYNC_STREAM_TARGET #else #error \ "TARGET_TO_MAX_DIFF can be enabled only with __AUDIO_RESAMPLE__ and PLL_TUNE_SAMPLE_RATE if both playback and capture streams exist" #endif #endif #ifdef USB_AUDIO_MULTIFUNC #error "TARGET_TO_MAX_DIFF can NOT be enabled with USB_AUDIO_MULTIFUNC" #endif #endif // TARGET_TO_MAX_DIFF #define VERBOSE_TRACE 0 // 0xFFFF #ifdef TIMER1_BASE #define TRACE_TIME(num, s, ...) \ TRACE(num + 1, "[%u] " s, FAST_TICKS_TO_US(hal_fast_sys_timer_get()), \ ##__VA_ARGS__) #else #define TRACE_TIME(num, s, ...) \ TRACE(num + 1, "[%X] " s, hal_sys_timer_get(), ##__VA_ARGS__) #endif #define USB_AUDIO_CPU_WAKE_USER HAL_CPU_WAKE_LOCK_USER_3 #define RECV_PAUSED_SAMPLE_RATE_FLAG (1 << 31) #define DIFF_ERR_THRESH_PLAYBACK (sample_rate_recv / 1000 / 2) #define DIFF_ERR_THRESH_CAPTURE (sample_rate_send / 1000 / 2) #define DIFF_SYNC_THRESH_PLAYBACK 10 #define DIFF_SYNC_THRESH_CAPTURE 10 #define DIFF_AVG_CNT 30 #define MAX_TARGET_RATIO 0.000020f #define MIN_VOLUME_VAL (TGT_VOLUME_LEVEL_MUTE) #define MAX_VOLUME_VAL (TGT_VOLUME_LEVEL_QTY - 1) #define MIN_CAP_VOLUME_VAL (TGT_ADC_VOL_LEVEL_0) #define MAX_CAP_VOLUME_VAL (TGT_ADC_VOL_LEVEL_QTY - 1) #define NOISE_GATING_INTERVAL MS_TO_TICKS(800) #define NOISE_GATING_THRESH_16BIT 3 // -80dB #define NOISE_GATING_THRESH_24BIT (NOISE_GATING_THRESH_16BIT << 8) #define NOISE_REDUCTION_INTERVAL MS_TO_TICKS(100) #define NOISE_REDUCTION_MATCH_CNT 200 #define NOISE_REDUCTION_THRESH_16BIT 100 // -50dB #define NOISE_REDUCTION_THRESH_24BIT (NOISE_REDUCTION_THRESH_16BIT << 8) #define CONFLICT_CMD_TRIG_COUNT 10 #define CONFLICT_CMD_TRIG_INTERVAL MS_TO_TICKS(20000) #define CONFLICT_STATE_RESET_INTERVAL MS_TO_TICKS(10000) #define CAPTURE_STABLE_INTERVAL MS_TO_TICKS(200) #define USB_MAX_XFER_INTERVAL MS_TO_TICKS(10) #define USB_XFER_ERR_REPORT_INTERVAL MS_TO_TICKS(5000) #define USB_AUDIO_MIN_DBVAL (-99) #define USB_AUDIO_VOL_UPDATE_STEP 0.00002 #ifndef USB_AUDIO_KEY_MAP #ifdef ANDROID_ACCESSORY_SPEC #ifdef ANDROID_VOICE_CMD_KEY #define USB_AUDIO_KEY_VOICE_CMD \ { \ USB_AUDIO_HID_VOICE_CMD, \ HAL_KEY_CODE_FN4, \ KEY_EVENT_SET2(DOWN, UP), \ }, #else #define USB_AUDIO_KEY_VOICE_CMD #endif #define USB_AUDIO_KEY_MAP \ { \ { \ USB_AUDIO_HID_PLAY_PAUSE, \ HAL_KEY_CODE_FN1, \ KEY_EVENT_SET2(DOWN, UP), \ }, \ { \ USB_AUDIO_HID_VOL_UP, \ HAL_KEY_CODE_FN2, \ KEY_EVENT_SET2(DOWN, UP), \ }, \ { \ USB_AUDIO_HID_VOL_DOWN, \ HAL_KEY_CODE_FN3, \ KEY_EVENT_SET2(DOWN, UP), \ }, \ USB_AUDIO_KEY_VOICE_CMD \ } #else #define USB_AUDIO_KEY_MAP \ { \ { \ USB_AUDIO_HID_PLAY_PAUSE, \ HAL_KEY_CODE_FN1, \ KEY_EVENT_SET(CLICK), \ }, \ { \ USB_AUDIO_HID_SCAN_NEXT, \ HAL_KEY_CODE_FN1, \ KEY_EVENT_SET(DOUBLECLICK), \ }, \ { \ USB_AUDIO_HID_SCAN_PREV, \ HAL_KEY_CODE_FN1, \ KEY_EVENT_SET(TRIPLECLICK), \ }, \ { \ USB_AUDIO_HID_VOL_UP, \ HAL_KEY_CODE_FN2, \ KEY_EVENT_SET4(CLICK, DOUBLECLICK, TRIPLECLICK, REPEAT), \ }, \ { \ USB_AUDIO_HID_VOL_DOWN, \ HAL_KEY_CODE_FN3, \ KEY_EVENT_SET4(CLICK, DOUBLECLICK, TRIPLECLICK, REPEAT), \ }, \ { \ USB_AUDIO_HID_HOOK_SWITCH, \ HAL_KEY_CODE_FN4, \ KEY_EVENT_SET(CLICK), \ }, \ } #endif #endif enum AUDIO_CMD_T { AUDIO_CMD_START_PLAY = 0, AUDIO_CMD_STOP_PLAY, AUDIO_CMD_START_CAPTURE, AUDIO_CMD_STOP_CAPTURE, AUDIO_CMD_SET_VOLUME, AUDIO_CMD_SET_CAP_VOLUME, AUDIO_CMD_MUTE_CTRL, AUDIO_CMD_CAP_MUTE_CTRL, AUDIO_CMD_USB_RESET, AUDIO_CMD_USB_DISCONNECT, AUDIO_CMD_USB_CONFIG, AUDIO_CMD_USB_SLEEP, AUDIO_CMD_USB_WAKEUP, AUDIO_CMD_RECV_PAUSE, AUDIO_CMD_RECV_CONTINUE, AUDIO_CMD_SET_RECV_RATE, AUDIO_CMD_SET_SEND_RATE, AUDIO_CMD_RESET_CODEC, AUDIO_CMD_NOISE_GATING, AUDIO_CMD_NOISE_REDUCTION, AUDIO_CMD_TUNE_RATE, AUDIO_CMD_SET_DSD_CFG, TEST_CMD_PERF_TEST_POWER, TEST_CMD_PA_ON_OFF, AUDIO_CMD_QTY }; enum AUDIO_ITF_STATE_T { AUDIO_ITF_STATE_STOPPED = 0, AUDIO_ITF_STATE_STARTED, }; enum AUDIO_STREAM_REQ_USER_T { AUDIO_STREAM_REQ_USB = 0, AUDIO_STREAM_REQ_ANC, AUDIO_STREAM_REQ_USER_QTY, AUDIO_STREAM_REQ_USER_ALL = AUDIO_STREAM_REQ_USER_QTY, }; enum AUDIO_STREAM_STATUS_T { AUDIO_STREAM_OPENED = 0, AUDIO_STREAM_STARTED, AUDIO_STREAM_STATUS_QTY }; enum AUDIO_STREAM_RUNNING_T { AUDIO_STREAM_RUNNING_NULL, AUDIO_STREAM_RUNNING_ENABLED, AUDIO_STREAM_RUNNING_DISABLED, }; enum CODEC_CONFIG_LOCK_USER_T { CODEC_CONFIG_LOCK_RESTART_PLAY, CODEC_CONFIG_LOCK_RESTART_CAP, CODEC_CONFIG_LOCK_USER_QTY }; enum CODEC_MUTE_USER_T { CODEC_MUTE_USER_CMD, CODEC_MUTE_USER_NOISE_GATING, CODEC_MUTE_USER_QTY, CODEC_MUTE_USER_ALL = CODEC_MUTE_USER_QTY, }; struct USB_AUDIO_KEY_MAP_T { enum USB_AUDIO_HID_EVENT_T hid_event; enum HAL_KEY_CODE_T key_code; uint32_t key_event_bitset; }; STATIC_ASSERT(8 * sizeof(((struct USB_AUDIO_KEY_MAP_T *)0)->key_event_bitset) >= HAL_KEY_EVENT_NUM, "key_event_bitset size is too small"); #ifdef USB_AUDIO_DYN_CFG static enum AUD_SAMPRATE_T sample_rate_play; static enum AUD_SAMPRATE_T sample_rate_cap; static enum AUD_SAMPRATE_T sample_rate_recv; static enum AUD_SAMPRATE_T sample_rate_send; static enum AUD_SAMPRATE_T new_sample_rate_recv; static enum AUD_SAMPRATE_T new_sample_rate_send; #ifdef AUDIO_PLAYBACK_24BIT static #ifndef CODEC_DSD const #endif uint8_t sample_size_play = 4; #else static uint8_t sample_size_play; #endif static const uint8_t sample_size_cap = SAMPLE_SIZE_CAPTURE; static uint8_t sample_size_recv; static const uint8_t sample_size_send = SAMPLE_SIZE_SEND; static uint8_t new_sample_size_recv; #else // !USB_AUDIO_DYN_CFG static const enum AUD_SAMPRATE_T sample_rate_play = SAMPLE_RATE_PLAYBACK; static const enum AUD_SAMPRATE_T sample_rate_cap = SAMPLE_RATE_CAPTURE; static const enum AUD_SAMPRATE_T sample_rate_recv = SAMPLE_RATE_RECV; static const enum AUD_SAMPRATE_T sample_rate_send = SAMPLE_RATE_SEND; static #ifndef CODEC_DSD const #endif uint8_t sample_size_play = SAMPLE_SIZE_PLAYBACK; static const uint8_t sample_size_cap = SAMPLE_SIZE_CAPTURE; static const uint8_t sample_size_recv = SAMPLE_SIZE_RECV; static const uint8_t sample_size_send = SAMPLE_SIZE_SEND; #endif // !USB_AUDIO_DYN_CFG #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) #ifdef USB_AUDIO_DYN_CFG static enum AUD_SAMPRATE_T sample_rate_ref_cap; #else // !USB_AUDIO_DYN_CFG #ifdef __AUDIO_RESAMPLE__ static const enum AUD_SAMPRATE_T sample_rate_ref_cap = SAMPLE_RATE_CAPTURE; #elif defined(USB_AUDIO_16K) static const enum AUD_SAMPRATE_T sample_rate_ref_cap = SAMPLE_RATE_CAPTURE; #else static const enum AUD_SAMPRATE_T sample_rate_ref_cap = (SAMPLE_RATE_RECV % AUD_SAMPRATE_8000) ? AUD_SAMPRATE_44100 : AUD_SAMPRATE_48000; #endif #endif // !USB_AUDIO_DYN_CFG #endif // (CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) static enum AUDIO_ITF_STATE_T playback_state = AUDIO_ITF_STATE_STOPPED; static enum AUDIO_ITF_STATE_T capture_state = AUDIO_ITF_STATE_STOPPED; static enum AUDIO_ITF_STATE_T recv_state = AUDIO_ITF_STATE_STOPPED; static enum AUDIO_ITF_STATE_T send_state = AUDIO_ITF_STATE_STOPPED; static uint8_t codec_stream_map[AUD_STREAM_NUM][AUDIO_STREAM_STATUS_QTY]; static uint8_t eq_opened; static enum AUDIO_STREAM_RUNNING_T streams_running_req; static uint8_t playback_paused; static uint8_t playback_conflicted; static uint8_t capture_conflicted; #ifdef NOISE_GATING enum NOISE_GATING_CMD_T { NOISE_GATING_CMD_NULL, NOISE_GATING_CMD_MUTE, NOISE_GATING_CMD_UNMUTE, }; static enum NOISE_GATING_CMD_T noise_gating_cmd = NOISE_GATING_CMD_NULL; static uint32_t last_high_signal_time; #ifdef NOISE_REDUCTION enum NOISE_REDUCTION_CMD_T { NOISE_REDUCTION_CMD_NULL, NOISE_REDUCTION_CMD_FIRE, NOISE_REDUCTION_CMD_RESTORE, }; static enum NOISE_REDUCTION_CMD_T noise_reduction_cmd = NOISE_REDUCTION_CMD_NULL; static bool nr_active; static bool prev_samp_positive[2]; static uint16_t prev_zero_diff[2][2]; static uint16_t cur_zero_diff[2][2]; static uint16_t nr_cont_cnt; static uint32_t last_nr_restore_time; static void restore_noise_reduction_status(void); #endif #endif static uint8_t *playback_buf; static uint32_t playback_size; static uint32_t playback_pos; #ifdef AUDIO_ANC_FB_MC static int32_t playback_samplerate_ratio; #endif static uint8_t *capture_buf; static uint32_t capture_size; static uint32_t capture_pos; static uint8_t *playback_eq_buf; static uint32_t playback_eq_size; #ifdef USB_AUDIO_DYN_CFG #ifdef KEEP_SAME_LATENCY static uint32_t playback_max_size; static uint32_t capture_max_size; static uint32_t usb_recv_max_size; static uint32_t usb_send_max_size; #endif static uint8_t playback_itf_set; static uint8_t capture_itf_set; #endif #ifdef SW_CAPTURE_RESAMPLE static RESAMPLE_ID resample_id; static bool resample_cap_enabled; static uint8_t *resample_history_buf; static uint32_t resample_history_size; static uint8_t *resample_input_buf; static uint32_t resample_input_size; #endif static uint8_t *usb_recv_buf; static uint32_t usb_recv_size; static uint32_t usb_recv_rpos; static uint32_t usb_recv_wpos; static uint8_t *usb_send_buf; static uint32_t usb_send_size; static uint32_t usb_send_rpos; static uint32_t usb_send_wpos; static uint8_t usb_configured; static uint8_t usb_recv_valid; static uint8_t usb_send_valid; static uint8_t usb_recv_init_rpos; static uint8_t usb_send_init_wpos; static uint8_t codec_play_seq; static uint8_t codec_cap_seq; static volatile uint8_t usb_recv_seq; static volatile uint8_t usb_send_seq; static uint8_t codec_play_valid; static uint8_t codec_cap_valid; #ifdef USB_AUDIO_MULTIFUNC static const uint8_t playback_vol = AUDIO_OUTPUT_VOLUME_DEFAULT; #else static uint8_t playback_vol; #endif static uint8_t new_playback_vol; static uint8_t new_mute_state; static uint8_t mute_user_map; STATIC_ASSERT(sizeof(mute_user_map) * 8 >= CODEC_MUTE_USER_QTY, "mute_user_map size too small"); static uint8_t capture_vol; static uint8_t new_capture_vol; static uint8_t new_cap_mute_state; static uint32_t last_usb_recv_err_time; static uint32_t usb_recv_err_cnt; static uint32_t usb_recv_ok_cnt; static uint32_t last_usb_send_err_time; static uint32_t usb_send_err_cnt; static uint32_t usb_send_ok_cnt; #ifdef USB_AUDIO_MULTIFUNC static uint8_t playback_conflicted2; static enum AUDIO_ITF_STATE_T recv2_state = AUDIO_ITF_STATE_STOPPED; static uint8_t *usb_recv2_buf; static uint32_t usb_recv2_size; static uint32_t usb_recv2_rpos; static uint32_t usb_recv2_wpos; static uint8_t usb_recv2_valid; static uint8_t usb_recv2_init_rpos; static uint8_t new_playback2_vol; static uint8_t new_mute2_state; static float new_playback_coef; static float new_playback2_coef; static float playback_coef; static float playback2_coef; static uint32_t last_usb_recv2_err_time; static uint32_t usb_recv2_err_cnt; static uint32_t usb_recv2_ok_cnt; static float playback_gain_to_float(uint32_t level); #endif static uint8_t codec_config_lock; STATIC_ASSERT(sizeof(codec_config_lock) * 8 >= CODEC_CONFIG_LOCK_USER_QTY, "codec_config_lock size too small"); static struct USB_AUDIO_STREAM_INFO_T playback_info; static struct USB_AUDIO_STREAM_INFO_T capture_info; static uint8_t nonconflict_start; static uint16_t conflict_cnt; static uint32_t conflict_time; static uint32_t nonconflict_time; static uint32_t codec_cap_start_time; static uint32_t last_usb_recv_time; static uint32_t last_usb_send_time; #define CMD_LIST_SIZE 30 static uint32_t cmd_list[CMD_LIST_SIZE]; static uint32_t cmd_watermark; static struct SAFE_QUEUE_T cmd_queue; #define EXTRACT_CMD(d) ((d)&0xFF) #define EXTRACT_SEQ(d) (((d) >> 8) & 0xFF) #define EXTRACT_ARG(d) (((d) >> 16) & 0xFF) #define MAKE_QUEUE_DATA(c, s, a) \ (((c)&0xFF) | ((s)&0xFF) << 8 | ((a)&0xFF) << 16) STATIC_ASSERT(AUDIO_CMD_QTY <= 0xFF, "audio cmd num exceeds size in queue"); STATIC_ASSERT(USB_AUDIO_STATE_EVENT_QTY <= 0xFF, "uaud evt num exceeds size in queue"); STATIC_ASSERT(sizeof(usb_recv_seq) <= 1, "usb recv seq exceeds size in queue"); STATIC_ASSERT(sizeof(usb_send_seq) <= 1, "usb send seq exceeds size in queue"); static const struct USB_AUDIO_KEY_MAP_T key_map[] = USB_AUDIO_KEY_MAP; #ifdef PERF_TEST_POWER_KEY static enum HAL_CODEC_PERF_TEST_POWER_T perft_power_type; #endif #ifdef PA_ON_OFF_KEY static bool pa_on_off_muted; #endif static float rate_tune_ratio[AUD_STREAM_NUM]; #ifdef DSD_SUPPORT static bool usb_dsd_enabled; static bool codec_dsd_enabled; static uint16_t usb_dsd_cont_cnt = 0; #ifdef CODEC_DSD static uint8_t dsd_saved_sample_size; #endif #endif #ifdef BT_USB_AUDIO_DUAL_MODE static USB_AUDIO_ENQUEUE_CMD_CALLBACK enqueue_cmd_cb; #endif static void enqueue_unique_cmd(enum AUDIO_CMD_T cmd); static void usb_audio_set_codec_volume(enum AUD_STREAM_T stream, uint8_t vol); static void usb_audio_cmd_tune_rate(enum AUD_STREAM_T stream); #if defined(CHIP_BEST1000) && defined(_DUAL_AUX_MIC_) extern void damic_init(void); extern void damic_deinit(void); // second-order IR filter short soir_filter(int32_t PcmValue) { float gain = 2.0F; const float NUM[3] = {0.013318022713065147, 0.02375408448278904, 0.010780527256429195}; const float DEN[3] = {1, -1.6983977556228638, 0.74625039100646973}; static float y0 = 0, y1 = 0, y2 = 0, x0 = 0, x1 = 0, x2 = 0; int32_t PcmOut = 0; // Left channel x0 = PcmValue * gain; y0 = x0 * NUM[0] + x1 * NUM[1] + x2 * NUM[2] - y1 * DEN[1] - y2 * DEN[2]; y2 = y1; y1 = y0; x2 = x1; x1 = x0; PcmOut = (int32_t)y0; PcmOut = __SSAT(PcmOut, 16); return (short)PcmOut; } #ifdef DUAL_AUX_MIC_MORE_FILTER // second-order IR filter short soir_filter1(int32_t PcmValue) { // float gain = 0.003031153698; const float NUM[3] = {0.013318022713065147, 0.02375408448278904, 0.010780527256429195}; const float DEN[3] = {1, -1.6983977556228638, 0.74625039100646973}; static float y0 = 0, y1 = 0, y2 = 0, x0 = 0, x1 = 0, x2 = 0; int32_t PcmOut = 0; // Left channel // x0 = PcmValue* gain; x0 = PcmValue; y0 = x0 * NUM[0] + x1 * NUM[1] + x2 * NUM[2] - y1 * DEN[1] - y2 * DEN[2]; y2 = y1; y1 = y0; x2 = x1; x1 = x0; PcmOut = (int32_t)y0; PcmOut = __SSAT(PcmOut, 16); return (short)PcmOut; } // second-order IR filter short soir_filter2(int32_t PcmValue) { // float gain = 0.003031153698; const float NUM[3] = {0.013318022713065147, 0.02375408448278904, 0.010780527256429195}; const float DEN[3] = {1, -1.6983977556228638, 0.74625039100646973}; static float y0 = 0, y1 = 0, y2 = 0, x0 = 0, x1 = 0, x2 = 0; int32_t PcmOut = 0; // Left channel // x0 = PcmValue* gain; x0 = PcmValue; y0 = x0 * NUM[0] + x1 * NUM[1] + x2 * NUM[2] - y1 * DEN[1] - y2 * DEN[2]; y2 = y1; y1 = y0; x2 = x1; x1 = x0; PcmOut = (int32_t)y0; PcmOut = __SSAT(PcmOut, 16); return (short)PcmOut; } #endif static float s_f_amic3_dc; static float s_f_amic4_dc; static short s_amic3_dc; static short s_amic4_dc; static void init_amic_dc(void) { s_amic3_dc = 0; s_amic4_dc = 0; s_f_amic3_dc = 0.0; s_f_amic4_dc = 0.0; } static void get_amic_dc(short *src, uint32_t samp_cnt, uint32_t step) { uint32_t i = 0; float u3_1 = 0.00001; float u3_2 = 1 - u3_1; float u4_1 = 0.00001; float u4_2 = 1 - u4_1; for (i = 0; i < samp_cnt; i += (2 << step)) { s_f_amic3_dc = u3_2 * s_f_amic3_dc + u3_1 * src[i << 1]; s_f_amic4_dc = u4_2 * s_f_amic4_dc + u4_1 * src[(i << 1) + 1]; } s_amic3_dc = __SSAT((int)s_f_amic3_dc, 16); s_amic4_dc = __SSAT((int)s_f_amic4_dc, 16); } #endif #ifdef FREQ_RESP_EQ #ifndef AUDIO_PLAYBACK_24BIT #error "FREQ_RESP_EQ requires AUDIO_PLAYBACK_24BIT" #endif #define FREQ_RESP_EQ_COEF_NUM 7 static float freq_resp_eq_coef[FREQ_RESP_EQ_COEF_NUM] = { // -0.000155, 0.000774, -0.003854, 0.994971, -0.003854, 0.000774, // -0.000155 -0.000138, 0.000687, -0.003426, 0.990852, -0.003426, 0.000687, -0.000138}; static int32_t freq_resp_eq_hist[2][(FREQ_RESP_EQ_COEF_NUM - 1) * 2]; static uint8_t freq_resp_eq_hist_idx; void freq_resp_eq_init(void) { int i; freq_resp_eq_hist_idx = 0; for (i = 0; i < ARRAY_SIZE(freq_resp_eq_hist[0]); i++) { freq_resp_eq_hist[0][i] = 0; freq_resp_eq_hist[1][i] = 0; } } int freq_resp_eq_run(uint8_t *buf, uint32_t len) { ASSERT(sample_size_play == 4, "Freq resp eq is running on 24-bit playback only"); if (sample_rate_play > AUD_SAMPRATE_96000) { // Sample rate higher than 96K will require higher system freq, which // consumes more power return 0; } int32_t *src_buf = (int32_t *)buf; int32_t *dst_buf = (int32_t *)buf; uint32_t mono_samp_num = len / 2 / sample_size_play; int32_t start_idx, in_idx, coef_idx; int32_t in_l, in_r; float out_l, out_r; uint8_t new_seq_idx = !freq_resp_eq_hist_idx; if (mono_samp_num >= (FREQ_RESP_EQ_COEF_NUM - 1)) { start_idx = (mono_samp_num - FREQ_RESP_EQ_COEF_NUM + 1) * 2; for (in_idx = 0; in_idx < (FREQ_RESP_EQ_COEF_NUM - 1) * 2; in_idx++) { freq_resp_eq_hist[new_seq_idx][in_idx] = src_buf[start_idx + in_idx]; } } else { start_idx = (FREQ_RESP_EQ_COEF_NUM - 1 - mono_samp_num) * 2; for (in_idx = 0; in_idx < start_idx; in_idx++) { freq_resp_eq_hist[new_seq_idx][in_idx] = freq_resp_eq_hist[freq_resp_eq_hist_idx][mono_samp_num * 2 + in_idx]; } for (in_idx = 0; in_idx < mono_samp_num * 2; in_idx++) { freq_resp_eq_hist[new_seq_idx][start_idx + in_idx] = src_buf[in_idx]; } } for (in_idx = mono_samp_num - 1; in_idx >= 0; in_idx--) { out_l = 0; out_r = 0; for (coef_idx = 0; coef_idx < FREQ_RESP_EQ_COEF_NUM; coef_idx++) { if (in_idx + coef_idx - FREQ_RESP_EQ_COEF_NUM + 1 >= 0) { in_l = src_buf[(in_idx + coef_idx - FREQ_RESP_EQ_COEF_NUM + 1) * 2]; in_r = src_buf[(in_idx + coef_idx - FREQ_RESP_EQ_COEF_NUM + 1) * 2 + 1]; } else { in_l = freq_resp_eq_hist[freq_resp_eq_hist_idx][(in_idx + coef_idx) * 2]; in_r = freq_resp_eq_hist[freq_resp_eq_hist_idx] [(in_idx + coef_idx) * 2 + 1]; } out_l += in_l * freq_resp_eq_coef[coef_idx]; out_r += in_r * freq_resp_eq_coef[coef_idx]; } // TODO: Is it really neccessary to round the float? // dst_buf[in_idx * 2] = __SSAT(ftoi_nearest(out_l), 24); // dst_buf[in_idx * 2 + 1] = __SSAT(ftoi_nearest(out_r), 24); dst_buf[in_idx * 2] = __SSAT((int32_t)out_l, 24); dst_buf[in_idx * 2 + 1] = __SSAT((int32_t)out_r, 24); } freq_resp_eq_hist_idx = new_seq_idx; return 0; } #endif // FREQ_RESP_EQ static enum AUD_BITS_T sample_size_to_enum_playback(uint32_t size) { if (size == 2) { return AUD_BITS_16; } else if (size == 4) { return AUD_BITS_24; } else { ASSERT(false, "%s: Invalid sample size: %u", __FUNCTION__, size); } return 0; } static enum AUD_BITS_T sample_size_to_enum_capture(uint32_t size) { if (size == 2) { return AUD_BITS_16; } else if (size == 4) { #ifdef USB_AUDIO_SEND_32BIT return AUD_BITS_32; #else return AUD_BITS_24; #endif } else { ASSERT(false, "%s: Invalid sample size: %u", __FUNCTION__, size); } return 0; } static enum AUD_CHANNEL_NUM_T chan_num_to_enum(uint32_t num) { return AUD_CHANNEL_NUM_1 + (num - 1); } static uint32_t POSSIBLY_UNUSED byte_to_samp_playback(uint32_t n) { #if defined(USB_AUDIO_DYN_CFG) || defined(CODEC_DSD) return n / sample_size_play / CHAN_NUM_PLAYBACK; #else return BYTE_TO_SAMP_PLAYBACK(n); #endif } static uint32_t POSSIBLY_UNUSED byte_to_samp_capture(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n / sample_size_cap / CHAN_NUM_CAPTURE; #else return BYTE_TO_SAMP_CAPTURE(n); #endif } static uint32_t POSSIBLY_UNUSED byte_to_samp_recv(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n / sample_size_recv / CHAN_NUM_RECV; #else return BYTE_TO_SAMP_RECV(n); #endif } static uint32_t POSSIBLY_UNUSED byte_to_samp_send(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n / sample_size_send / CHAN_NUM_SEND; #else return BYTE_TO_SAMP_SEND(n); #endif } static uint32_t POSSIBLY_UNUSED samp_to_byte_playback(uint32_t n) { #if defined(USB_AUDIO_DYN_CFG) || defined(CODEC_DSD) return n * sample_size_play * CHAN_NUM_PLAYBACK; #else return SAMP_TO_BYTE_PLAYBACK(n); #endif } static uint32_t POSSIBLY_UNUSED samp_to_byte_capture(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n * sample_size_cap * CHAN_NUM_CAPTURE; #else return SAMP_TO_BYTE_CAPTURE(n); #endif } static uint32_t POSSIBLY_UNUSED samp_to_byte_recv(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n * sample_size_recv * CHAN_NUM_RECV; #else return SAMP_TO_BYTE_RECV(n); #endif } static uint32_t POSSIBLY_UNUSED samp_to_byte_send(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG return n * sample_size_send * CHAN_NUM_SEND; #else return SAMP_TO_BYTE_SEND(n); #endif } static uint32_t playback_to_recv_len(uint32_t n) { #if defined(USB_AUDIO_DYN_CFG) || defined(CODEC_DSD) uint32_t len; // 1) When changing recv sample rate, the play stream will be stopped and then // restarted. // So when calculating the len, play sample rate has been changed according // to recv sample rate. // 2) Play and recv sample rates are integral multiple of each other. len = samp_to_byte_recv(byte_to_samp_playback(n)); if (sample_rate_recv == sample_rate_play) { return len; } else if (sample_rate_recv < sample_rate_play) { return len / (sample_rate_play / sample_rate_recv); } else { return len * (sample_rate_recv / sample_rate_play); } #else return PLAYBACK_TO_RECV_LEN(n); #endif } static uint32_t capture_to_send_len(uint32_t n) { #ifdef USB_AUDIO_DYN_CFG uint32_t len; enum AUD_SAMPRATE_T send_rate; enum AUD_SAMPRATE_T cap_rate; // 1) When changing send sample rate, the cap stream will not be changed if // the play stream is active. // Moreover, the cap stream might be changed if changing recv sample rate // (and then play sample rate). So when calculating the len, cap sample // rate might be inconsistent with send sample rate. // 2) Resample might be applied to the cap stream. Cap and send sample rates // have no integral multiple relationship. send_rate = sample_rate_send; cap_rate = sample_rate_cap; len = samp_to_byte_send(byte_to_samp_capture(n)); if (send_rate == cap_rate) { return len; } else { // Unlikely to overflow for the max send_rate is 48000 return ALIGN((len * send_rate + cap_rate - 1) / cap_rate, sample_size_send * CHAN_NUM_SEND); } #else return CAPTURE_TO_SEND_LEN(n); #endif } #ifdef USB_AUDIO_DYN_CFG static uint32_t POSSIBLY_UNUSED capture_to_ref_len(uint32_t n) { uint32_t len; len = samp_to_byte_send(byte_to_samp_capture(n)); #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) // Capture reference sample rate and capture sample rate are integral multiple // of each other. if (sample_rate_ref_cap == sample_rate_cap) { return len; } else if (sample_rate_ref_cap < sample_rate_cap) { return len / (sample_rate_cap / sample_rate_ref_cap); } else { return len * (sample_rate_ref_cap / sample_rate_cap); } #else return len; #endif } #ifdef KEEP_SAME_LATENCY static uint32_t calc_usb_recv_size(enum AUD_SAMPRATE_T rate, uint8_t sample_size) { uint32_t size; size = (SAMP_RATE_TO_FRAME_SIZE(rate) * sample_size * CHAN_NUM_RECV) * (usb_recv_max_size / MAX_FRAME_SIZE_RECV); return NON_EXP_ALIGN(size, RECV_BUFF_ALIGN); } static uint32_t calc_usb_send_size(enum AUD_SAMPRATE_T rate) { uint32_t size; size = samp_to_byte_send(SAMP_RATE_TO_FRAME_SIZE(rate)) * usb_send_max_size / MAX_FRAME_SIZE_SEND; return NON_EXP_ALIGN(size, SEND_BUFF_ALIGN); } static uint32_t calc_playback_size(enum AUD_SAMPRATE_T rate) { uint32_t size; size = samp_to_byte_playback(SAMP_RATE_TO_FRAME_SIZE(rate)) * (playback_max_size / MAX_FRAME_SIZE_PLAYBACK); return NON_EXP_ALIGN(size, DAC_BUFF_ALIGN); } static uint32_t calc_capture_size(enum AUD_SAMPRATE_T rate) { uint32_t size; size = samp_to_byte_capture(SAMP_RATE_TO_FRAME_SIZE(rate)) * (capture_max_size / MAX_FRAME_SIZE_CAPTURE); return NON_EXP_ALIGN(size, ADC_BUFF_ALIGN); } #endif #endif static void record_conflict(int conflicted) { uint32_t lock; uint32_t interval; bool reset = false; lock = int_lock(); if (conflicted) { nonconflict_start = 0; if (conflict_cnt == 0) { conflict_time = hal_sys_timer_get(); } conflict_cnt++; if (conflict_cnt >= CONFLICT_CMD_TRIG_COUNT) { interval = hal_sys_timer_get() - conflict_time; if (interval < CONFLICT_CMD_TRIG_INTERVAL) { // TRACE(2,"RESET CODEC: conflict cnt=%u interval=%u ms", conflict_cnt, // TICKS_TO_MS(interval)); reset = true; } conflict_cnt = 0; } } else { if (nonconflict_start == 0) { nonconflict_start = 1; if (conflict_cnt) { nonconflict_time = hal_sys_timer_get(); } } else { if (conflict_cnt) { interval = hal_sys_timer_get() - nonconflict_time; if (interval >= CONFLICT_STATE_RESET_INTERVAL) { // TRACE(2,"RESET CONFLICT STATE: conflict cnt=%u nonconflict // interval=%u ms", conflict_cnt, TICKS_TO_MS(interval)); conflict_cnt = 0; } } } } int_unlock(lock); if (reset) { // Avoid invoking cmd callback when irq is locked enqueue_unique_cmd(AUDIO_CMD_RESET_CODEC); } } static void reset_conflict(void) { uint32_t lock; lock = int_lock(); conflict_cnt = 0; nonconflict_start = 0; int_unlock(lock); } uint8_t usb_audio_get_eq_index(AUDIO_EQ_TYPE_T audio_eq_type, uint8_t anc_status) { uint8_t index_eq = 0; #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_DAC_IIR_EQ_PROCESS__) || defined(__HW_IIR_EQ_PROCESS__) switch (audio_eq_type) { #if defined(__SW_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_SW_IIR: { if (anc_status) { index_eq = audio_eq_sw_iir_index + 1; } else { index_eq = audio_eq_sw_iir_index; } } break; #endif #if defined(__HW_FIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_FIR: { #ifdef USB_AUDIO_DYN_CFG if (sample_rate_recv == AUD_SAMPRATE_44100) { index_eq = 0; } else if (sample_rate_recv == AUD_SAMPRATE_48000) { index_eq = 1; } else if (sample_rate_recv == AUD_SAMPRATE_96000) { index_eq = 2; } else if (sample_rate_recv == AUD_SAMPRATE_192000) { index_eq = 3; } else { ASSERT(0, "[%s] sample_rate_recv(%d) is not supported", __func__, sample_rate_recv); } audio_eq_hw_fir_index = index_eq; #else index_eq = audio_eq_hw_fir_index; #endif if (anc_status) { index_eq = index_eq + 4; } } break; #endif #if defined(__HW_DAC_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_DAC_IIR: { if (anc_status) { index_eq = audio_eq_hw_dac_iir_index + 1; } else { index_eq = audio_eq_hw_dac_iir_index; } } break; #endif #if defined(__HW_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_IIR: { if (anc_status) { index_eq = audio_eq_hw_iir_index + 1; } else { index_eq = audio_eq_hw_iir_index; } } break; #endif default: { ASSERT(false, "[%s]Error eq type!", __func__); } } #endif return index_eq; } uint32_t usb_audio_set_eq(AUDIO_EQ_TYPE_T audio_eq_type, uint8_t index) { const FIR_CFG_T *fir_cfg = NULL; const IIR_CFG_T *iir_cfg = NULL; TRACE(3, "[%s]audio_eq_type=%d,index=%d", __func__, audio_eq_type, index); #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_DAC_IIR_EQ_PROCESS__) || defined(__HW_IIR_EQ_PROCESS__) switch (audio_eq_type) { #if defined(__SW_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_SW_IIR: { if (index >= EQ_SW_IIR_LIST_NUM) { TRACE(2, "[%s] index[%d] > EQ_SW_IIR_LIST_NUM", __func__, index); return 1; } iir_cfg = audio_eq_sw_iir_cfg_list[index]; } break; #endif #if defined(__HW_FIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_FIR: { if (index >= EQ_HW_FIR_LIST_NUM) { TRACE(2, "[%s] index[%d] > EQ_HW_FIR_LIST_NUM", __func__, index); return 1; } fir_cfg = audio_eq_hw_fir_cfg_list[index]; } break; #endif #if defined(__HW_DAC_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_DAC_IIR: { if (index >= EQ_HW_DAC_IIR_LIST_NUM) { TRACE(2, "[%s] index[%d] > EQ_HW_DAC_IIR_LIST_NUM", __func__, index); return 1; } iir_cfg = audio_eq_hw_dac_iir_cfg_list[index]; } break; #endif #if defined(__HW_IIR_EQ_PROCESS__) case AUDIO_EQ_TYPE_HW_IIR: { if (index >= EQ_HW_IIR_LIST_NUM) { TRACE(2, "[%s] index[%d] > EQ_HW_IIR_LIST_NUM", __func__, index); return 1; } iir_cfg = audio_eq_hw_iir_cfg_list[index]; } break; #endif default: { ASSERT(false, "[%s]Error eq type!", __func__); } } #endif return audio_eq_set_cfg(fir_cfg, iir_cfg, audio_eq_type); } static void set_codec_config_status(enum CODEC_CONFIG_LOCK_USER_T user, bool lock) { if (lock) { codec_config_lock |= (1 << user); } else { codec_config_lock &= ~(1 << user); } } static void usb_audio_codec_mute(enum CODEC_MUTE_USER_T user) { TRACE(3, "%s: user=%d map=0x%02X", __FUNCTION__, user, mute_user_map); if (user >= CODEC_MUTE_USER_QTY || mute_user_map == 0) { af_stream_mute(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, true); } if (user < CODEC_MUTE_USER_QTY) { mute_user_map |= (1 << user); } } static void usb_audio_codec_unmute(enum CODEC_MUTE_USER_T user) { uint8_t old_map; STATIC_ASSERT(sizeof(old_map) * 8 >= CODEC_MUTE_USER_QTY, "old_map size too small"); TRACE(3, "%s: user=%d map=0x%02X", __FUNCTION__, user, mute_user_map); old_map = mute_user_map; if (user < CODEC_MUTE_USER_QTY) { mute_user_map &= ~(1 << user); } if (user >= CODEC_MUTE_USER_QTY || (old_map && mute_user_map == 0)) { af_stream_mute(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, false); } } #ifdef AUDIO_ANC_FB_MC #define DELAY_SAMPLE_MC (33 * 2) // 2:ch static int32_t delay_buf[DELAY_SAMPLE_MC]; static int32_t mid_p_8_old_l = 0; static int32_t mid_p_8_old_r = 0; static uint32_t audio_mc_data_playback(uint8_t *buf, uint32_t mc_len_bytes) { // uint32_t begin_time; // uint32_t end_time; // begin_time = hal_sys_timer_get(); // TRACE(1,"cancel: %d",begin_time); float left_gain; float right_gain; uint32_t playback_len_bytes; int i, j, k; int delay_sample; hal_codec_get_dac_gain(&left_gain, &right_gain); // TRACE(1,"playback_samplerate_ratio: %d",playback_samplerate_ratio); // TRACE(1,"left_gain: %d",(int)(left_gain*(1<<12))); // TRACE(1,"right_gain: %d",(int)(right_gain*(1<<12))); playback_len_bytes = mc_len_bytes / playback_samplerate_ratio; if (sample_size_play == 2) { int16_t *sour_p = (int16_t *)(playback_buf + playback_size / 2); int16_t *mid_p = (int16_t *)(buf); int16_t *mid_p_8 = (int16_t *)(buf + mc_len_bytes - mc_len_bytes / 8); int16_t *dest_p = (int16_t *)buf; int i, j, k; if (buf == (playback_buf + playback_size)) { sour_p = (int16_t *)playback_buf; } delay_sample = DELAY_SAMPLE_MC; for (i = 0, j = 0; i < delay_sample; i = i + 2) { mid_p[j++] = delay_buf[i]; mid_p[j++] = delay_buf[i + 1]; } for (i = 0; i < playback_len_bytes / 2 - delay_sample; i = i + 2) { mid_p[j++] = sour_p[i]; mid_p[j++] = sour_p[i + 1]; } for (j = 0; i < playback_len_bytes / 2; i = i + 2) { delay_buf[j++] = sour_p[i]; delay_buf[j++] = sour_p[i + 1]; } if (playback_samplerate_ratio <= 8) { for (i = 0, j = 0; i < playback_len_bytes / 2; i = i + 2 * (8 / playback_samplerate_ratio)) { mid_p_8[j++] = mid_p[i]; mid_p_8[j++] = mid_p[i + 1]; } } else { for (i = 0, j = 0; i < playback_len_bytes / 2; i = i + 2) { for (k = 0; k < playback_samplerate_ratio / 8; k++) { mid_p_8[j++] = mid_p[i]; mid_p_8[j++] = mid_p[i + 1]; } } } anc_mc_run_stereo((uint8_t *)mid_p_8, mc_len_bytes / 8, left_gain, right_gain, AUD_BITS_16); for (i = 0, j = 0; i < (mc_len_bytes / 8) / 2; i = i + 2) { float delta_l = (mid_p_8[i] - mid_p_8_old_l) / 8.0f; float delta_r = (mid_p_8[i + 1] - mid_p_8_old_r) / 8.0f; for (k = 0; k < 8; k++) { dest_p[j++] = mid_p_8_old_l + (int32_t)(delta_l * k); dest_p[j++] = mid_p_8_old_r + (int32_t)(delta_r * k); } mid_p_8_old_l = mid_p_8[i]; mid_p_8_old_r = mid_p_8[i + 1]; } } else if (sample_size_play == 4) { int32_t *sour_p = (int32_t *)(playback_buf + playback_size / 2); int32_t *mid_p = (int32_t *)(buf); int32_t *mid_p_8 = (int32_t *)(buf + mc_len_bytes - mc_len_bytes / 8); int32_t *dest_p = (int32_t *)buf; if (buf == (playback_buf + playback_size)) { sour_p = (int32_t *)playback_buf; } delay_sample = DELAY_SAMPLE_MC; for (i = 0, j = 0; i < delay_sample; i = i + 2) { mid_p[j++] = delay_buf[i]; mid_p[j++] = delay_buf[i + 1]; } for (i = 0; i < playback_len_bytes / 4 - delay_sample; i = i + 2) { mid_p[j++] = sour_p[i]; mid_p[j++] = sour_p[i + 1]; } for (j = 0; i < playback_len_bytes / 4; i = i + 2) { delay_buf[j++] = sour_p[i]; delay_buf[j++] = sour_p[i + 1]; } if (playback_samplerate_ratio <= 8) { for (i = 0, j = 0; i < playback_len_bytes / 4; i = i + 2 * (8 / playback_samplerate_ratio)) { mid_p_8[j++] = mid_p[i]; mid_p_8[j++] = mid_p[i + 1]; } } else { for (i = 0, j = 0; i < playback_len_bytes / 4; i = i + 2) { for (k = 0; k < playback_samplerate_ratio / 8; k++) { mid_p_8[j++] = mid_p[i]; mid_p_8[j++] = mid_p[i + 1]; } } } anc_mc_run_stereo((uint8_t *)mid_p_8, mc_len_bytes / 8, left_gain, right_gain, AUD_BITS_24); for (i = 0, j = 0; i < (mc_len_bytes / 8) / 4; i = i + 2) { float delta_l = (mid_p_8[i] - mid_p_8_old_l) / 8.0f; float delta_r = (mid_p_8[i + 1] - mid_p_8_old_r) / 8.0f; for (k = 0; k < 8; k++) { dest_p[j++] = mid_p_8_old_l + (int32_t)(delta_l * k); dest_p[j++] = mid_p_8_old_r + (int32_t)(delta_r * k); } mid_p_8_old_l = mid_p_8[i]; mid_p_8_old_r = mid_p_8[i + 1]; } } // end_time = hal_sys_timer_get(); // TRACE(2,"%s:run time: %d", __FUNCTION__, end_time-begin_time); return 0; } #endif static uint32_t usb_audio_data_playback(uint8_t *buf, uint32_t len) { uint32_t usb_len; uint32_t old_rpos, saved_old_rpos, new_rpos, wpos; uint8_t recv_valid, init_pos; uint8_t conflicted; uint32_t reset_len = usb_recv_size / 2; #ifdef USB_AUDIO_MULTIFUNC uint32_t old_rpos2, saved_old_rpos2, new_rpos2, wpos2; uint8_t recv2_valid, init_pos2; uint8_t conflicted2; uint32_t reset_len2 = usb_recv2_size / 2; #endif uint32_t play_next; uint32_t lock; uint8_t *conv_buf; uint32_t cur_time; uint32_t usb_time; usb_time = last_usb_recv_time; cur_time = hal_sys_timer_get(); //---------------------------------------- // Speech processing start //---------------------------------------- #ifdef USB_AUDIO_SPEECH speech_process_playback_run(buf, &len); #endif //---------------------------------------- // Speech processing end //---------------------------------------- ASSERT(((uint32_t)buf & 0x3) == 0, "%s: Invalid buf: %p", __FUNCTION__, buf); // playback is valid when reaching here codec_play_valid = 1; init_pos = 0; // Allow to play till the end of the buffer when itf stopped if (usb_recv_valid && !(recv_state == AUDIO_ITF_STATE_STOPPED && usb_recv_rpos == usb_recv_wpos)) { recv_valid = 1; if (usb_recv_init_rpos == 0) { init_pos = 1; } } else { recv_valid = 0; } #ifdef USB_AUDIO_MULTIFUNC init_pos2 = 0; if (usb_recv2_valid && !(recv2_state == AUDIO_ITF_STATE_STOPPED && usb_recv2_rpos == usb_recv2_wpos)) { recv2_valid = 1; if (usb_recv2_init_rpos == 0) { init_pos2 = 1; } } else { recv2_valid = 0; } #endif if (codec_play_seq != usb_recv_seq || playback_state == AUDIO_ITF_STATE_STOPPED || #ifdef USB_AUDIO_MULTIFUNC (recv_valid == 0 && recv2_valid == 0) || #else recv_valid == 0 || #endif cur_time - usb_time > USB_MAX_XFER_INTERVAL) { _invalid_play: zero_mem32(buf, len); conv_buf = buf; // If usb recv is stopped, set usb_recv_rpos to the value of usb_recv_wpos // -- avoid playing noise. Otherwise set usb_recv_rpos to 0 -- avoid buffer // conflicts at usb recv startup. new_rpos = (recv_state == AUDIO_ITF_STATE_STOPPED) ? usb_recv_wpos : 0; conflicted = 0; #ifdef USB_AUDIO_MULTIFUNC new_rpos2 = (recv2_state == AUDIO_ITF_STATE_STOPPED) ? usb_recv2_wpos : 0; conflicted2 = 0; #endif goto _conv_end; } //---------------------------------------- // Check conflict //---------------------------------------- usb_len = playback_to_recv_len(len); conflicted = 0; #ifdef USB_AUDIO_MULTIFUNC conflicted2 = 0; #endif lock = int_lock(); wpos = usb_recv_wpos; if (init_pos) { old_rpos = wpos + reset_len; if (old_rpos >= usb_recv_size) { old_rpos -= usb_recv_size; } usb_recv_rpos = old_rpos; usb_recv_init_rpos = 1; } else { old_rpos = usb_recv_rpos; } saved_old_rpos = old_rpos; new_rpos = usb_recv_rpos + usb_len; if (new_rpos >= usb_recv_size) { new_rpos -= usb_recv_size; } if (recv_valid && init_pos == 0) { if (old_rpos <= wpos) { if (new_rpos < old_rpos || wpos < new_rpos) { if (recv_state == AUDIO_ITF_STATE_STOPPED) { if (new_rpos < old_rpos) { zero_mem(usb_recv_buf + wpos, usb_recv_size - wpos); zero_mem(usb_recv_buf, new_rpos); } else { zero_mem(usb_recv_buf + wpos, new_rpos - wpos); } wpos = new_rpos; usb_recv_wpos = new_rpos; } else { conflicted = 1; } } } else { if (wpos < new_rpos && new_rpos < old_rpos) { if (recv_state == AUDIO_ITF_STATE_STOPPED) { zero_mem(usb_recv_buf + wpos, new_rpos - wpos); wpos = new_rpos; usb_recv_wpos = new_rpos; } else { conflicted = 1; } } } if (conflicted) { // Reset read position old_rpos = wpos + reset_len; if (old_rpos >= usb_recv_size) { old_rpos -= usb_recv_size; } new_rpos = old_rpos + usb_len; if (new_rpos >= usb_recv_size) { new_rpos -= usb_recv_size; } // Update global read position usb_recv_rpos = old_rpos; } } #ifdef USB_AUDIO_MULTIFUNC wpos2 = usb_recv2_wpos; if (init_pos2) { old_rpos2 = wpos2 + reset_len2; if (old_rpos2 >= usb_recv2_size) { old_rpos2 -= usb_recv2_size; } usb_recv2_rpos = old_rpos2; usb_recv2_init_rpos = 1; } else { old_rpos2 = usb_recv2_rpos; } saved_old_rpos2 = old_rpos2; new_rpos2 = usb_recv2_rpos + usb_len; if (new_rpos2 >= usb_recv2_size) { new_rpos2 -= usb_recv2_size; } if (recv2_valid && init_pos2 == 0) { if (old_rpos2 <= wpos2) { if (new_rpos2 < old_rpos2 || wpos2 < new_rpos2) { if (recv2_state == AUDIO_ITF_STATE_STOPPED) { if (new_rpos2 < old_rpos2) { zero_mem(usb_recv2_buf + wpos2, usb_recv2_size - wpos2); zero_mem(usb_recv2_buf, new_rpos2); } else { zero_mem(usb_recv2_buf + wpos2, new_rpos2 - wpos2); } wpos2 = new_rpos2; usb_recv2_wpos = new_rpos2; } else { conflicted2 = 1; } } } else { if (wpos2 < new_rpos2 && new_rpos2 < old_rpos2) { if (recv2_state == AUDIO_ITF_STATE_STOPPED) { zero_mem(usb_recv2_buf + wpos2, new_rpos2 - wpos2); wpos2 = new_rpos2; usb_recv2_wpos = new_rpos2; } else { conflicted2 = 1; } } } if (conflicted2) { // Reset read position old_rpos2 = wpos2 + reset_len2; if (old_rpos2 >= usb_recv2_size) { old_rpos2 -= usb_recv2_size; } new_rpos2 = old_rpos2 + usb_len; if (new_rpos2 >= usb_recv2_size) { new_rpos2 -= usb_recv2_size; } // Update global read position usb_recv2_rpos = old_rpos2; } } #endif int_unlock(lock); if (conflicted) { TRACE(4, "playback: Error: rpos=%u goes beyond wpos=%u with usb_len=%u. Reset " "to %u", saved_old_rpos, wpos, usb_len, old_rpos); } #ifdef USB_AUDIO_MULTIFUNC if (conflicted2) { TRACE(4, "playback: Error: rpos2=%u goes beyond wpos2=%u with usb_len=%u. " "Reset to %u", saved_old_rpos2, wpos2, usb_len, old_rpos2); } #endif #if (VERBOSE_TRACE & (1 << 0)) { int hw_play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); uint32_t play_pos = buf - playback_buf; #ifdef USB_AUDIO_MULTIFUNC if (recv_valid == 0) { old_rpos = -1; wpos = -1; } if (recv2_valid == 0) { old_rpos2 = -1; wpos2 = -1; } TRACE_TIME(8, "playback: rpos=%d/%d usb_len=%d wpos=%d/%d play_pos=%d len=%d " "hw_play_pos=%d", old_rpos, old_rpos2, usb_len, wpos, wpos2, play_pos, len, hw_play_pos); #else TRACE_TIME(6, "playback: rpos=%d usb_len=%d wpos=%d play_pos=%d len=%d " "hw_play_pos=%d", old_rpos, usb_len, wpos, play_pos, len, hw_play_pos); #endif } #endif if (codec_play_seq != usb_recv_seq) { goto _invalid_play; } #ifdef USB_AUDIO_MULTIFUNC record_conflict(conflicted || conflicted2); #else record_conflict(conflicted); #endif //---------------------------------------- // USB->CODEC stream format conversion start //---------------------------------------- conv_buf = buf; #ifdef USB_AUDIO_MULTIFUNC { uint8_t POSSIBLY_UNUSED *cur_buf, *buf_end, *usb_cur_buf, *usb_buf_end, *usb_cur_buf2, *usb_buf_end2; uint32_t codec_step, usb_step; float cur_gain, new_gain, cur_gain2, new_gain2, gain_step; cur_buf = conv_buf; buf_end = conv_buf + len; usb_cur_buf = usb_recv_buf + old_rpos; usb_buf_end = usb_recv_buf + usb_recv_size; usb_cur_buf2 = usb_recv2_buf + old_rpos2; usb_buf_end2 = usb_recv2_buf + usb_recv2_size; cur_gain = playback_coef; new_gain = new_playback_coef; cur_gain2 = playback2_coef; new_gain2 = new_playback2_coef; gain_step = USB_AUDIO_VOL_UPDATE_STEP; ASSERT(sample_rate_play == sample_rate_recv, "2:1: Invalid sample_rate_play=%u sample_rate_recv=%u", sample_rate_play, sample_rate_recv); if (0) { } else if (sample_size_play == 4 && (sample_size_recv == 4 || sample_size_recv == 3 || sample_size_recv == 2)) { int32_t left, right; int32_t left2, right2; if (sample_size_recv == 4) { usb_step = 8; } else if (sample_size_recv == 3) { usb_step = 6; } else { usb_step = 4; } codec_step = 8; while (cur_buf + codec_step <= buf_end) { if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } if (usb_cur_buf2 + usb_step > usb_buf_end2) { usb_cur_buf2 = usb_recv2_buf; } if (recv_valid) { if (usb_step == 8) { left = *(int32_t *)usb_cur_buf; right = *((int32_t *)usb_cur_buf + 1); } else if (usb_step == 6) { left = ((usb_cur_buf[0] << 8) | (usb_cur_buf[1] << 16) | (usb_cur_buf[2] << 24)); right = ((usb_cur_buf[3] << 8) | (usb_cur_buf[4] << 16) | (usb_cur_buf[5] << 24)); } else { left = *(int16_t *)usb_cur_buf << 16; right = *((int16_t *)usb_cur_buf + 1) << 16; } if (cur_gain > new_gain) { cur_gain -= gain_step; if (cur_gain < new_gain) { cur_gain = new_gain; } } else if (cur_gain < new_gain) { cur_gain += gain_step; if (cur_gain > new_gain) { cur_gain = new_gain; } } left = (int32_t)(left * cur_gain); right = (int32_t)(right * cur_gain); } else { left = right = 0; } if (recv2_valid) { if (usb_step == 8) { left2 = *(int32_t *)usb_cur_buf2; right2 = *((int32_t *)usb_cur_buf2 + 1); } else if (usb_step == 6) { left2 = ((usb_cur_buf2[0] << 8) | (usb_cur_buf2[1] << 16) | (usb_cur_buf2[2] << 24)); right2 = ((usb_cur_buf2[3] << 8) | (usb_cur_buf2[4] << 16) | (usb_cur_buf2[5] << 24)); } else { left2 = *(int16_t *)usb_cur_buf2 << 16; right2 = *((int16_t *)usb_cur_buf2 + 1) << 16; } if (cur_gain2 > new_gain2) { cur_gain2 -= gain_step; if (cur_gain2 < new_gain2) { cur_gain2 = new_gain2; } } else if (cur_gain2 < new_gain2) { cur_gain2 += gain_step; if (cur_gain2 > new_gain2) { cur_gain2 = new_gain2; } } left2 = (int32_t)(left2 * cur_gain2); right2 = (int32_t)(right2 * cur_gain2); } else { left2 = right2 = 0; } left = __QADD(left, left2); right = __QADD(right, right2); // Convert to 24-bit sample left >>= 8; right >>= 8; *(int32_t *)cur_buf = left; *((int32_t *)cur_buf + 1) = right; cur_buf += codec_step; usb_cur_buf += usb_step; usb_cur_buf2 += usb_step; } } else if (sample_size_play == 2 && sample_size_recv == 2) { int32_t left, right; int32_t left2, right2; usb_step = 4; codec_step = 4; while (cur_buf + codec_step <= buf_end) { if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } if (usb_cur_buf2 + usb_step > usb_buf_end2) { usb_cur_buf2 = usb_recv2_buf; } if (recv_valid) { left = *(int16_t *)usb_cur_buf; right = *((int16_t *)usb_cur_buf + 1); if (cur_gain > new_gain) { cur_gain -= gain_step; if (cur_gain < new_gain) { cur_gain = new_gain; } } else if (cur_gain < new_gain) { cur_gain += gain_step; if (cur_gain > new_gain) { cur_gain = new_gain; } } left = (int32_t)(left * cur_gain); right = (int32_t)(right * cur_gain); } else { left = right = 0; } if (recv2_valid) { left2 = *(int16_t *)usb_cur_buf2; right2 = *((int16_t *)usb_cur_buf2 + 1); if (cur_gain2 > new_gain2) { cur_gain2 -= gain_step; if (cur_gain2 < new_gain2) { cur_gain2 = new_gain2; } } else if (cur_gain2 < new_gain2) { cur_gain2 += gain_step; if (cur_gain2 > new_gain2) { cur_gain2 = new_gain2; } } left2 = (int32_t)(left2 * cur_gain2); right2 = (int32_t)(right2 * cur_gain2); } else { left2 = right2 = 0; } left = __SSAT(left + left2, 16); right = __SSAT(right + right2, 16); *(int16_t *)cur_buf = left; *((int16_t *)cur_buf + 1) = right; cur_buf += codec_step; usb_cur_buf += usb_step; } } else { ASSERT(false, "2:3: Invalid sample_size_play=%u sample_size_recv=%u", sample_size_play, sample_size_recv); } playback_coef = cur_gain; playback2_coef = cur_gain2; } #else { uint8_t POSSIBLY_UNUSED *cur_buf, *buf_end, *usb_cur_buf, *usb_buf_end; uint32_t codec_step, usb_step; bool down_sampling = false; cur_buf = conv_buf; buf_end = conv_buf + len; usb_cur_buf = usb_recv_buf + old_rpos; usb_buf_end = usb_recv_buf + usb_recv_size; if (0) { #ifdef CODEC_DSD } else if (codec_dsd_enabled) { ASSERT(sample_size_play == 2, "Bad DSD playback sample size: %u", sample_size_play); ASSERT(sample_size_recv == 4 || sample_size_recv == 3, "Bad DSD recv sample size: %u", sample_size_recv); uint32_t left, right; if (sample_size_recv == 4) { usb_step = 8; } else { usb_step = 6; } codec_step = 4; while (cur_buf + codec_step <= buf_end) { if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } if (usb_step == 8) { left = *(uint32_t *)usb_cur_buf; right = *((uint32_t *)usb_cur_buf + 1); } else { left = ((usb_cur_buf[0] << 8) | (usb_cur_buf[1] << 16)); right = ((usb_cur_buf[3] << 8) | (usb_cur_buf[4] << 16)); } left = __RBIT(left) >> 8; right = __RBIT(right) >> 8; *(uint16_t *)cur_buf = left; *((uint16_t *)cur_buf + 1) = right; cur_buf += codec_step; usb_cur_buf += usb_step; } #endif } else if (sample_size_play == 4 && (sample_size_recv == 4 || sample_size_recv == 3 || sample_size_recv == 2)) { int32_t left, right; if (sample_size_recv == 4) { usb_step = 8; } else if (sample_size_recv == 3) { usb_step = 6; } else { usb_step = 4; } if ((sample_rate_play == 96000 && sample_rate_recv == 48000) || (sample_rate_play == 88200 && sample_rate_recv == 44100)) { codec_step = 16; } else if (sample_rate_play == sample_rate_recv) { codec_step = 8; } else if (sample_rate_play == 96000 && sample_rate_recv == 192000) { codec_step = 8; down_sampling = true; } else { ASSERT(false, "1: Invalid sample_rate_play=%u sample_rate_recv=%u", sample_rate_play, sample_rate_recv); } while (cur_buf + codec_step <= buf_end) { if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } if (usb_step == 8) { left = *(int32_t *)usb_cur_buf; right = *((int32_t *)usb_cur_buf + 1); } else if (usb_step == 6) { left = ((usb_cur_buf[0] << 8) | (usb_cur_buf[1] << 16) | (usb_cur_buf[2] << 24)); right = ((usb_cur_buf[3] << 8) | (usb_cur_buf[4] << 16) | (usb_cur_buf[5] << 24)); } else { left = *(int16_t *)usb_cur_buf << 16; right = *((int16_t *)usb_cur_buf + 1) << 16; } // Convert to 24-bit sample left >>= 8; right >>= 8; if (down_sampling) { int32_t left_next, right_next; usb_cur_buf += usb_step; if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } if (usb_step == 8) { left_next = *(int32_t *)usb_cur_buf; right_next = *((int32_t *)usb_cur_buf + 1); } else if (usb_step == 6) { left_next = ((usb_cur_buf[0] << 8) | (usb_cur_buf[1] << 16) | (usb_cur_buf[2] << 24)); right_next = ((usb_cur_buf[3] << 8) | (usb_cur_buf[4] << 16) | (usb_cur_buf[5] << 24)); } else { left_next = *(int16_t *)usb_cur_buf << 16; right_next = *((int16_t *)usb_cur_buf + 1) << 16; } // Convert to 24-bit sample left_next >>= 8; right_next >>= 8; // The addition of two 24-bit integers will not saturate left = (left + left_next) / 2; right = (right + right_next) / 2; } *(int32_t *)cur_buf = left; *((int32_t *)cur_buf + 1) = right; if (codec_step == 16) { *((int32_t *)cur_buf + 2) = left; *((int32_t *)cur_buf + 3) = right; } cur_buf += codec_step; usb_cur_buf += usb_step; } } else if (sample_size_play == 2 && sample_size_recv == 2) { int16_t left, right; usb_step = 4; if ((sample_rate_play == 96000 && sample_rate_recv == 48000) || (sample_rate_play == 88200 && sample_rate_recv == 44100)) { codec_step = 8; } else if (sample_rate_play == sample_rate_recv) { codec_step = 4; } else if (sample_rate_play == 96000 && sample_rate_recv == 192000) { codec_step = 4; down_sampling = true; } else { ASSERT(false, "2: Invalid sample_rate_play=%u sample_rate_recv=%u", sample_rate_play, sample_rate_recv); } while (cur_buf + codec_step <= buf_end) { if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } left = *(int16_t *)usb_cur_buf; right = *((int16_t *)usb_cur_buf + 1); if (down_sampling) { // Use 32-bit integers to avoid saturation int32_t left32, right32; usb_cur_buf += usb_step; if (usb_cur_buf + usb_step > usb_buf_end) { usb_cur_buf = usb_recv_buf; } left32 = *(int16_t *)usb_cur_buf; right32 = *((int16_t *)usb_cur_buf + 1); left = (left + left32) / 2; right = (right + right32) / 2; } *(int16_t *)cur_buf = left; *((int16_t *)cur_buf + 1) = right; if (codec_step == 8) { *((int16_t *)cur_buf + 2) = left; *((int16_t *)cur_buf + 3) = right; } cur_buf += codec_step; usb_cur_buf += usb_step; } } else { ASSERT(false, "3: Invalid sample_size_play=%u sample_size_recv=%u", sample_size_play, sample_size_recv); } } #endif // !USB_AUDIO_MULTIFUNC //---------------------------------------- // USB->CODEC stream format conversion end //---------------------------------------- _conv_end: play_next = buf + len - playback_buf; if (play_next >= playback_size) { play_next -= playback_size; } lock = int_lock(); if (codec_play_seq == usb_recv_seq) { #ifdef USB_AUDIO_MULTIFUNC if (playback_state == AUDIO_ITF_STATE_STARTED) { if (recv_valid) { usb_recv_rpos = new_rpos; } if (recv2_valid) { usb_recv2_rpos = new_rpos2; } } else { if (recv_valid) { usb_recv_rpos = 0; } if (recv2_valid) { usb_recv2_rpos = 0; } } if (conflicted) { playback_conflicted = conflicted; } if (conflicted2) { playback_conflicted2 = conflicted2; } #else if (playback_state == AUDIO_ITF_STATE_STARTED) { usb_recv_rpos = new_rpos; } else { usb_recv_rpos = 0; } if (conflicted) { playback_conflicted = conflicted; } #endif playback_pos = play_next; } int_unlock(lock); //---------------------------------------- // Audio processing start //---------------------------------------- #ifdef FREQ_RESP_EQ freq_resp_eq_run(conv_buf, len); #endif #if defined(__HW_FIR_DSD_PROCESS__) if (codec_dsd_enabled) { dsd_process(conv_buf, len); } #endif #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_IIR_EQ_PROCESS__) if (eq_opened) { audio_process_run(conv_buf, len); } #endif // If conv_buf != buf, copy the output to buf //---------------------------------------- // Audio processing end //---------------------------------------- #ifdef NOISE_GATING bool noise_mute = true; #ifdef NOISE_REDUCTION bool nr_fire = true; uint8_t chan = 0; #endif if (sample_size_play == 2) { int16_t *samp = (int16_t *)buf; for (uint32_t i = 0; i < len / 2; i++) { if (ABS(samp[i]) >= NOISE_GATING_THRESH_16BIT) { noise_mute = false; break; } // NOISE_REDUCTION is unstable for 16-bit streams for unknown reasons. // Skip by now. } } else { int32_t *samp = (int32_t *)buf; for (uint32_t i = 0; i < len / 4; i++) { if (ABS(samp[i]) >= NOISE_GATING_THRESH_24BIT) { noise_mute = false; #ifndef NOISE_REDUCTION break; #endif } #ifdef NOISE_REDUCTION if (nr_fire) { if (ABS(samp[i]) >= NOISE_REDUCTION_THRESH_24BIT) { nr_fire = false; } else { cur_zero_diff[chan][0]++; cur_zero_diff[chan][1]++; if ((prev_samp_positive[chan] && samp[i] < 0) || (!prev_samp_positive[chan] && samp[i] >= 0)) { if (ABS(cur_zero_diff[chan][prev_samp_positive[chan]] - prev_zero_diff[chan][prev_samp_positive[chan]]) < 2) { if (nr_cont_cnt < NOISE_REDUCTION_MATCH_CNT) { nr_cont_cnt++; } } else if (nr_cont_cnt > 2) { nr_fire = false; } prev_zero_diff[chan][prev_samp_positive[chan]] = cur_zero_diff[chan][prev_samp_positive[chan]]; cur_zero_diff[chan][prev_samp_positive[chan]] = 0; } prev_samp_positive[chan] = (samp[i] >= 0); // Switch channel chan = !chan; } } #endif } } #ifdef NOISE_REDUCTION if (noise_mute) { nr_fire = false; } if (nr_fire) { if (nr_cont_cnt >= NOISE_REDUCTION_MATCH_CNT && !nr_active && noise_reduction_cmd != NOISE_REDUCTION_CMD_FIRE) { if (cur_time - last_nr_restore_time >= NOISE_REDUCTION_INTERVAL) { TRACE(8, "\nFire noise reduction: cur0=%u/%u cur1=%u/%u prev0=%u/%u " "prev1=%u/%u\n", cur_zero_diff[0][0], cur_zero_diff[0][1], cur_zero_diff[1][0], cur_zero_diff[1][1], prev_zero_diff[0][0], prev_zero_diff[0][1], prev_zero_diff[1][0], prev_zero_diff[1][1]); noise_reduction_cmd = NOISE_REDUCTION_CMD_FIRE; enqueue_unique_cmd(AUDIO_CMD_NOISE_REDUCTION); } } } else { if (nr_active && noise_reduction_cmd != NOISE_REDUCTION_CMD_RESTORE) { TRACE(8, "\nRestore noise reduction: cur0=%u/%u cur1=%u/%u prev0=%u/%u " "prev1=%u/%u\n", cur_zero_diff[0][0], cur_zero_diff[0][1], cur_zero_diff[1][0], cur_zero_diff[1][1], prev_zero_diff[0][0], prev_zero_diff[0][1], prev_zero_diff[1][0], prev_zero_diff[1][1]); noise_reduction_cmd = NOISE_REDUCTION_CMD_RESTORE; enqueue_unique_cmd(AUDIO_CMD_NOISE_REDUCTION); } memset(prev_zero_diff, 0, sizeof(prev_zero_diff)); memset(cur_zero_diff, 0, sizeof(cur_zero_diff)); nr_cont_cnt = 0; last_nr_restore_time = cur_time; } #endif if (noise_mute) { if ((mute_user_map & (1 << CODEC_MUTE_USER_NOISE_GATING)) == 0 && noise_gating_cmd != NOISE_GATING_CMD_MUTE) { if (cur_time - last_high_signal_time >= NOISE_GATING_INTERVAL) { noise_gating_cmd = NOISE_GATING_CMD_MUTE; enqueue_unique_cmd(AUDIO_CMD_NOISE_GATING); } } } else { if ((mute_user_map & (1 << CODEC_MUTE_USER_NOISE_GATING)) && noise_gating_cmd != NOISE_GATING_CMD_UNMUTE) { noise_gating_cmd = NOISE_GATING_CMD_UNMUTE; enqueue_unique_cmd(AUDIO_CMD_NOISE_GATING); } last_high_signal_time = cur_time; } #endif #if (VERBOSE_TRACE & (1 << 1)) { int hw_play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); TRACE_TIME(2, "playbackEnd: playback_pos=%u hw_play_pos=%d", playback_pos, hw_play_pos); } #endif return 0; } static uint32_t usb_audio_data_capture(uint8_t *buf, uint32_t len) { uint32_t usb_len; uint32_t old_wpos, saved_old_wpos, new_wpos, rpos; uint8_t init_pos; uint8_t conflicted; uint32_t reset_len = usb_send_size / 2; uint32_t cap_next; uint32_t lock; uint8_t *conv_buf; uint32_t cur_time; uint32_t usb_time; #ifdef SW_CAPTURE_RESAMPLE enum RESAMPLE_STATUS_T ret; struct RESAMPLE_IO_BUF_T io; uint32_t in_size; uint32_t out_size; uint32_t resample_frame_len = 0; #endif usb_time = last_usb_send_time; cur_time = hal_sys_timer_get(); ASSERT(((uint32_t)buf & 0x3) == 0, "%s: Invalid buf: %p", __FUNCTION__, buf); if (codec_cap_valid == 0 && cur_time - codec_cap_start_time >= CAPTURE_STABLE_INTERVAL) { codec_cap_valid = 1; } if (codec_cap_seq != usb_send_seq || capture_state == AUDIO_ITF_STATE_STOPPED || send_state == AUDIO_ITF_STATE_STOPPED || codec_cap_valid == 0 || usb_send_valid == 0 || cur_time - usb_time > USB_MAX_XFER_INTERVAL) { _invalid_cap: new_wpos = 0; conflicted = 0; goto _conv_end; } if (usb_send_init_wpos) { init_pos = 0; } else { init_pos = 1; } //---------------------------------------- // Check conflict //---------------------------------------- usb_len = capture_to_send_len(len); conflicted = 0; lock = int_lock(); rpos = usb_send_rpos; if (init_pos) { old_wpos = rpos + reset_len; if (old_wpos >= usb_send_size) { old_wpos -= usb_send_size; } usb_send_wpos = old_wpos; usb_send_init_wpos = 1; } else { old_wpos = usb_send_wpos; } saved_old_wpos = old_wpos; new_wpos = usb_send_wpos + usb_len; if (new_wpos >= usb_send_size) { new_wpos -= usb_send_size; } if (init_pos == 0) { if (old_wpos <= rpos) { if (new_wpos < old_wpos || rpos < new_wpos) { conflicted = 1; } } else { if (rpos < new_wpos && new_wpos < old_wpos) { conflicted = 1; } } if (conflicted) { // Reset write position old_wpos = rpos + reset_len; if (old_wpos >= usb_send_size) { old_wpos -= usb_send_size; } new_wpos = old_wpos + usb_len; if (new_wpos >= usb_send_size) { new_wpos -= usb_send_size; } // Update global write position usb_send_wpos = old_wpos; } } int_unlock(lock); if (conflicted) { TRACE(4, "capture: Error: wpos=%u goes beyond rpos=%u with usb_len=%u. Reset " "to %u", saved_old_wpos, rpos, usb_len, old_wpos); } #if (VERBOSE_TRACE & (1 << 2)) TRACE_TIME(5, "capture: wpos=%u usb_len=%u rpos=%u cap_pos=%u len=%u", old_wpos, usb_len, rpos, buf + len - capture_buf, len); #endif if (codec_cap_seq != usb_send_seq) { goto _invalid_cap; } record_conflict(conflicted); //---------------------------------------- // Audio processing start //---------------------------------------- // TODO ... //---------------------------------------- // Audio processing end //---------------------------------------- //---------------------------------------- // Speech processing start //---------------------------------------- #ifdef USB_AUDIO_SPEECH speech_process_capture_run(buf, &len); #endif //---------------------------------------- // Speech processing end //---------------------------------------- //---------------------------------------- // CODEC->USB stream format conversion start //---------------------------------------- conv_buf = buf; { uint8_t POSSIBLY_UNUSED *cur_buf, *buf_end, *dst_buf_start, *dst_cur_buf, *dst_buf_end; cur_buf = conv_buf; buf_end = conv_buf + len; #ifdef SW_CAPTURE_RESAMPLE if (resample_cap_enabled) { #if (CHAN_NUM_CAPTURE == CHAN_NUM_SEND) #if (defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_))) // codec capture buffer --(ref rate conversion)--> resample input buffer // --(resample)--> usb send buffer #ifdef USB_AUDIO_DYN_CFG // Resample frame len is the capture reference len after reference rate // conversion resample_frame_len = capture_to_ref_len(len); #else // Resample frame len is the capture len resample_frame_len = len; #endif ASSERT(resample_frame_len <= resample_input_size, "resample_input_size too small: %u len=%u resample_frame_len=%u", resample_input_size, len, resample_frame_len); dst_buf_start = resample_input_buf; dst_cur_buf = resample_input_buf; dst_buf_end = resample_input_buf + resample_frame_len; #else // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) // codec capture buffer --(resample)--> usb send buffer resample_input_buf = cur_buf; // Resample frame len is the capture len resample_frame_len = len; dst_buf_start = cur_buf; dst_cur_buf = cur_buf; dst_buf_end = cur_buf + len; #endif // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) #elif (CHAN_NUM_CAPTURE == 2) && (CHAN_NUM_SEND == 1) // codec capture buffer --(chan num conversion)--> codec capture buffer // --(resample)--> usb send buffer resample_input_buf = cur_buf; // Resample frame len is half of the capture len resample_frame_len = len / 2; dst_buf_start = cur_buf; dst_cur_buf = cur_buf; dst_buf_end = cur_buf + resample_frame_len; #elif (CHAN_NUM_CAPTURE == 1) && (CHAN_NUM_SEND == 2) // codec capture buffer --(resample)--> usb send buffer --(chan num // conversion)--> usb send buffer // Resample frame len is the capture len resample_frame_len = len; io.in = cur_buf; io.in_size = resample_frame_len; io.out = usb_send_buf + old_wpos; io.out_size = usb_len / 2; io.out_cyclic_start = usb_send_buf; io.out_cyclic_end = usb_send_buf + usb_send_size; ret = audio_resample_ex_run(resample_id, &io, &in_size, &out_size); ASSERT((ret == RESAMPLE_STATUS_IN_EMPTY || ret == RESAMPLE_STATUS_DONE) && io.out_size >= out_size, "Failed to resample: %d io.out_size=%u in_size=%u out_size=%u", ret, io.out_size, in_size, out_size); uint32_t diff = usb_len - out_size * 2; if (new_wpos >= diff) { new_wpos -= diff; } else { new_wpos = new_wpos + usb_send_size - diff; } #if (VERBOSE_TRACE & (1 << 3)) TRACE(5, "cap_resample: new_wpos=%u, in: %u -> %u, out: %u -> %u", new_wpos, io.in_size, in_size, io.out_size, out_size); #endif dst_buf_start = usb_send_buf; dst_cur_buf = usb_send_buf + old_wpos; dst_buf_end = usb_send_buf + usb_send_size; cur_buf = dst_cur_buf; buf_end = cur_buf + out_size; if (buf_end >= usb_send_buf + usb_send_size) { buf_end -= usb_send_size; } #else #error "Unsupported CHAN_NUM_CAPTURE and CHAN_NUM_SEND configuration" #endif } else #endif // SW_CAPTURE_RESAMPLE { dst_buf_start = usb_send_buf; dst_cur_buf = usb_send_buf + old_wpos; dst_buf_end = usb_send_buf + usb_send_size; } #if defined(CHIP_BEST1000) && defined(_DUAL_AUX_MIC_) // Assuming codec adc records stereo data, and usb sends 48K/44.1K stereo // data #if (CHAN_NUM_CAPTURE != 2) || (CHAN_NUM_SEND != 2) #error "Unsupported CHAN_NUM_CAPTURE and CHAN_NUM_SEND configuration" #endif { #define MERGE_VER 2 #if (MERGE_VER == 2) #define THRES_MIC3 32500 #else #define THRES_MIC3 27168 #endif #define SHIFT_BITS 4 uint32_t i = 0; short *BufSrc = (short *)cur_buf; short *BufDst = (short *)dst_cur_buf; short *BufDstStart = (short *)dst_buf_start; short *BufDstEnd = (short *)dst_buf_end; int32_t PcmValue = 0; int32_t BufSrcRVal = 0; uint32_t step; // TRACE(3,"%s - %d, %d", __func__, BufSrc[0], BufSrc[1]); // TRACE(2,"%s - %d", __func__, TICKS_TO_MS(cur_time)); if (sample_rate_cap == 384000 || sample_rate_cap == 352800) { step = 2; } else if (sample_rate_cap == 192000 || sample_rate_cap == 176400) { step = 1; } else { ASSERT(false, "1: Invalid sample_rate_cap=%u sample_rate_ref_cap=%u " "sample_rate_send=%u", sample_rate_cap, sample_rate_ref_cap, sample_rate_send); } get_amic_dc(BufSrc, len >> 2, step); for (i = 0; i < (len >> 2); i += step) { if (step == 2) { if (!(i & 0x1)) { PcmValue = ((int32_t)(BufSrc[i << 1])); BufSrcRVal = ((int32_t)(BufSrc[(i << 1) + 1])); #if (MERGE_VER == 2) if ((PcmValue < THRES_MIC3) && (PcmValue > -THRES_MIC3)) { PcmValue = (PcmValue - s_amic3_dc) >> SHIFT_BITS; } else { PcmValue = BufSrcRVal - s_amic4_dc; } #else // (MERGE_VER == 1) PcmValue -= s_amic3_dc; if ((PcmValue < THRES_MIC3) && (PcmValue > -THRES_MIC3)) { PcmValue >>= SHIFT_BITS; } else { PcmValue = BufSrcRVal - s_amic4_dc; } #endif // MERGE_VER PcmValue = soir_filter(PcmValue); #ifdef DUAL_AUX_MIC_MORE_FILTER PcmValue = soir_filter1(PcmValue); PcmValue = soir_filter2(PcmValue); #endif if (!(i & 7)) { if (BufDst + 2 > BufDstEnd) { BufDst = BufDstStart; } *BufDst++ = PcmValue; *BufDst++ = PcmValue; } } } else { if (!(i & 0x1)) { PcmValue = ((int32_t)(BufSrc[i << 1])); BufSrcRVal = ((int32_t)(BufSrc[(i << 1) + 1])); #if (MERGE_VER == 2) if ((PcmValue < THRES_MIC3) && (PcmValue > -THRES_MIC3)) { PcmValue = (PcmValue - s_amic3_dc) >> SHIFT_BITS; } else { PcmValue = BufSrcRVal - s_amic4_dc; } #else // (MERGE_VER == 1) PcmValue -= s_amic3_dc; if ((PcmValue < THRES_MIC3) && (PcmValue > -THRES_MIC3)) { PcmValue >>= SHIFT_BITS; } else { PcmValue = BufSrcRVal - s_amic4_dc; } #endif // MERGE_VER PcmValue = soir_filter(PcmValue); #ifdef DUAL_AUX_MIC_MORE_FILTER PcmValue = soir_filter1(PcmValue); PcmValue = soir_filter2(PcmValue); #endif if (!(i & 3)) { if (BufDst + 2 > BufDstEnd) { BufDst = BufDstStart; } *BufDst++ = PcmValue; *BufDst++ = PcmValue; } } } } } #elif defined(CHIP_BEST1000) && defined(ANC_APP) // Assuming codec adc records stereo data, and usb sends 48K/44.1K stereo // data #if (CHAN_NUM_CAPTURE != 2) || (CHAN_NUM_SEND != 2) #error "Unsupported CHAN_NUM_CAPTURE and CHAN_NUM_SEND configuration" #endif if ((sample_rate_ref_cap == 48000 || sample_rate_ref_cap == 44100) && (sample_rate_cap == sample_rate_ref_cap * 2 || sample_rate_cap == sample_rate_ref_cap * 4 || sample_rate_cap == sample_rate_ref_cap * 8 || sample_rate_cap == sample_rate_ref_cap * 16)) { uint32_t POSSIBLY_UNUSED factor = sample_rate_cap / sample_rate_ref_cap; int32_t POSSIBLY_UNUSED left = 0; int32_t POSSIBLY_UNUSED right = 0; uint32_t step = factor * 4; while (cur_buf + step <= buf_end) { if (dst_cur_buf + 4 > dst_buf_end) { dst_cur_buf = dst_buf_start; } // Downsampling the adc data #if 1 left = 0; right = 0; for (int i = 0; i < factor; i++) { left += *(int16_t *)(cur_buf + 4 * i); right += *(int16_t *)(cur_buf + 4 * i + 2); } *(int16_t *)dst_cur_buf = left / factor; *(int16_t *)(dst_cur_buf + 2) = right / factor; #else *(int16_t *)dst_cur_buf = *(int16_t *)cur_buf; *(int16_t *)(dst_cur_buf + 2) = *(int16_t *)(cur_buf + 2); #endif // Move to next data dst_cur_buf += 4; cur_buf += step; } } else { ASSERT(false, "2: Invalid sample_rate_cap=%u sample_rate_ref_cap=%u " "sample_rate_send=%u", sample_rate_cap, sample_rate_ref_cap, sample_rate_send); } #else // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) #ifndef SW_CAPTURE_RESAMPLE ASSERT(sample_rate_cap == sample_rate_send, "3: Invalid sample_rate_cap=%u sample_rate_send=%u", sample_rate_cap, sample_rate_send); #endif // When USB_AUDIO_SPEECH is enable, buf after algorithm shoule be CHAN_NUM_SEND, // do not need to convert any more. #if (CHAN_NUM_CAPTURE == 2) && (CHAN_NUM_SEND == 1) && \ !defined(USB_AUDIO_SPEECH) // Assuming codec adc always records stereo data while (cur_buf + 4 <= buf_end) { // Copy left channel data if (dst_cur_buf + 2 > dst_buf_end) { dst_cur_buf = dst_buf_start; } *(int16_t *)dst_cur_buf = *(int16_t *)cur_buf; // Move to next data dst_cur_buf += 2; cur_buf += 4; } #elif (CHAN_NUM_CAPTURE == 1) && (CHAN_NUM_SEND == 2) && \ !defined(USB_AUDIO_SPEECH) // Assuming codec adc always records mono data #ifdef SW_CAPTURE_RESAMPLE #if (CHAN_NUM_CAPTURE == 1) && (CHAN_NUM_SEND == 2) if (resample_cap_enabled) { // ASSERT(cur_buf == dst_cur_buf, "Bad assumption"); uint32_t src_len; if (buf_end < cur_buf) { src_len = buf_end + usb_send_size - cur_buf; } else { src_len = buf_end - cur_buf; } cur_buf = buf_end - 2; if (cur_buf < dst_buf_start) { cur_buf += usb_send_size; } dst_cur_buf += src_len * 2 - 4; if (dst_cur_buf >= dst_buf_end) { dst_cur_buf -= usb_send_size; } while (src_len > 0) { *(int16_t *)dst_cur_buf = *(int16_t *)cur_buf; *(int16_t *)(dst_cur_buf + 2) = *(int16_t *)cur_buf; // Move to next data src_len -= 2; cur_buf -= 2; if (cur_buf < dst_buf_start) { cur_buf += usb_send_size; } dst_cur_buf -= 4; if (dst_cur_buf < dst_buf_start) { dst_cur_buf += usb_send_size; } } } else #endif #endif { while (cur_buf + 2 <= buf_end) { // Duplicate the mono data if (dst_cur_buf + 4 > dst_buf_end) { dst_cur_buf = dst_buf_start; } *(int16_t *)dst_cur_buf = *(int16_t *)cur_buf; *(int16_t *)(dst_cur_buf + 2) = *(int16_t *)cur_buf; // Move to next data dst_cur_buf += 4; cur_buf += 2; } } #else // (CHAN_NUM_CAPTURE == CHAN_NUM_SEND) // The channel numbers of codec adc and USB data are the same if (sample_size_cap == sample_size_send) { #if ((CHAN_NUM_CAPTURE & 1) == 0) #define COPY_MEM(dst, src, size) copy_mem32(dst, src, size) #else #define COPY_MEM(dst, src, size) copy_mem16(dst, src, size) #endif if (dst_cur_buf != cur_buf) { if (dst_cur_buf + len <= dst_buf_end) { COPY_MEM(dst_cur_buf, cur_buf, len); } else { uint32_t copy_len; if (dst_cur_buf >= dst_buf_end) { copy_len = 0; } else { copy_len = dst_buf_end - dst_cur_buf; COPY_MEM(dst_cur_buf, cur_buf, copy_len); } COPY_MEM(dst_buf_start, cur_buf + copy_len, len - copy_len); } } #undef COPY_MEM } else if (sample_size_cap == 4 && sample_size_send == 3) { uint32_t codec_step, usb_step; uint32_t ch; codec_step = CHAN_NUM_CAPTURE * 4; usb_step = CHAN_NUM_SEND * 3; while (cur_buf + codec_step <= buf_end) { if (dst_cur_buf + usb_step > dst_buf_end) { dst_cur_buf = dst_buf_start; } for (ch = 0; ch < CHAN_NUM_CAPTURE; ch++) { *(uint16_t *)dst_cur_buf = *(uint16_t *)cur_buf; *(uint8_t *)(dst_cur_buf + 2) = *(uint8_t *)(cur_buf + 2); // Move to next channel dst_cur_buf += 3; cur_buf += 4; } } } else { ASSERT(false, "4: Invalid sample_size_cap=%u sample_size_send=%u", sample_size_cap, sample_size_send); } #endif // (CHAN_NUM_CAPTURE == CHAN_NUM_SEND) #endif // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) #ifdef SW_CAPTURE_RESAMPLE #if !((CHAN_NUM_CAPTURE == 1) && (CHAN_NUM_SEND == 2)) if (resample_cap_enabled) { io.in = resample_input_buf; io.in_size = resample_frame_len; io.out = usb_send_buf + old_wpos; io.out_size = usb_len; io.out_cyclic_start = usb_send_buf; io.out_cyclic_end = usb_send_buf + usb_send_size; ret = audio_resample_ex_run(resample_id, &io, &in_size, &out_size); ASSERT((ret == RESAMPLE_STATUS_IN_EMPTY || ret == RESAMPLE_STATUS_DONE) && io.out_size >= out_size, "Failed to resample: %d io.out_size=%u io.in_size=%u in_size=%u " "out_size=%u", ret, io.out_size, io.in_size, in_size, out_size); uint32_t diff = usb_len - out_size; if (new_wpos >= diff) { new_wpos -= diff; } else { new_wpos = new_wpos + usb_send_size - diff; } #if (VERBOSE_TRACE & (1 << 3)) TRACE(5, "cap_resample: new_wpos=%u, in: %u -> %u, out: %u -> %u", new_wpos, io.in_size, in_size, io.out_size, out_size); #endif } #endif #endif } //---------------------------------------- // CODEC->USB stream format conversion end //---------------------------------------- _conv_end: cap_next = buf + len - capture_buf; if (cap_next >= capture_size) { cap_next -= capture_size; } lock = int_lock(); if (codec_cap_seq == usb_send_seq) { if (capture_state == AUDIO_ITF_STATE_STARTED) { usb_send_wpos = new_wpos; } else { usb_send_wpos = 0; } capture_pos = cap_next; if (conflicted) { capture_conflicted = conflicted; } } int_unlock(lock); #if (VERBOSE_TRACE & (1 << 4)) TRACE_TIME(0, "captureEnd"); #endif return 0; } static void update_playback_sync_info(void) { playback_info.err_thresh = DIFF_ERR_THRESH_PLAYBACK; playback_info.samp_rate = sample_rate_play; playback_info.samp_cnt = byte_to_samp_recv(usb_recv_size); #ifdef TARGET_TO_MAX_DIFF playback_info.max_target_thresh = playback_info.samp_cnt / 2; playback_info.diff_target = byte_to_samp_recv(playback_to_recv_len(playback_size / 2)) + playback_info.samp_cnt / 2; playback_info.diff_target = usb_audio_sync_normalize_diff( -playback_info.diff_target, playback_info.samp_cnt); #endif TRACE(4, "%s: rate=%u cnt=%u (%u)", __FUNCTION__, playback_info.samp_rate, playback_info.samp_cnt, usb_recv_size); } static void update_capture_sync_info(void) { capture_info.err_thresh = DIFF_ERR_THRESH_CAPTURE; capture_info.samp_rate = sample_rate_cap; capture_info.samp_cnt = byte_to_samp_send(usb_send_size); #ifdef TARGET_TO_MAX_DIFF capture_info.max_target_thresh = capture_info.samp_cnt / 2; capture_info.diff_target = byte_to_samp_send(capture_to_send_len(capture_size / 2)) + capture_info.samp_cnt / 2; capture_info.diff_target = usb_audio_sync_normalize_diff( capture_info.diff_target, capture_info.samp_cnt); #endif TRACE(4, "%s: rate=%u cnt=%u (%u)", __FUNCTION__, capture_info.samp_rate, capture_info.samp_cnt, usb_send_size); } static int usb_audio_open_codec_stream(enum AUD_STREAM_T stream, enum AUDIO_STREAM_REQ_USER_T user) { int ret = 0; struct AF_STREAM_CONFIG_T stream_cfg; TRACE(4, "%s: stream=%d user=%d map=0x%x", __FUNCTION__, stream, user, codec_stream_map[stream][AUDIO_STREAM_OPENED]); if (user >= AUDIO_STREAM_REQ_USER_QTY || codec_stream_map[stream][AUDIO_STREAM_OPENED] == 0) { memset(&stream_cfg, 0, sizeof(stream_cfg)); if (stream == AUD_STREAM_PLAYBACK) { #if defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY) playback_size = calc_playback_size(sample_rate_play); #endif update_playback_sync_info(); #ifdef CODEC_DSD if (codec_dsd_enabled) { stream_cfg.bits = AUD_BITS_24; } else #endif { stream_cfg.bits = sample_size_to_enum_playback(sample_size_play); } stream_cfg.sample_rate = sample_rate_play; stream_cfg.channel_num = chan_num_to_enum(CHAN_NUM_PLAYBACK); #ifdef USB_I2S_APP #if defined(USB_I2S_ID) && (USB_I2S_ID == 0) stream_cfg.device = AUD_STREAM_USE_I2S0_MASTER; #else stream_cfg.device = AUD_STREAM_USE_I2S1_MASTER; #endif #else stream_cfg.device = AUD_STREAM_USE_INT_CODEC; #endif stream_cfg.vol = playback_vol; stream_cfg.handler = usb_audio_data_playback; stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER; stream_cfg.data_ptr = playback_buf; stream_cfg.data_size = playback_size; // TRACE(3,"[%s] sample_rate: %d, bits = %d", __func__, // stream_cfg.sample_rate, stream_cfg.bits); ret = af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg); ASSERT(ret == 0, "af_stream_open playback failed: %d", ret); #ifdef AUDIO_ANC_FB_MC stream_cfg.bits = sample_size_to_enum_playback(sample_size_play); stream_cfg.sample_rate = sample_rate_play; stream_cfg.channel_num = chan_num_to_enum(CHAN_NUM_PLAYBACK); stream_cfg.device = AUD_STREAM_USE_MC; stream_cfg.vol = playback_vol; stream_cfg.handler = audio_mc_data_playback; stream_cfg.io_path = AUD_OUTPUT_PATH_SPEAKER; stream_cfg.data_ptr = playback_buf + playback_size; mid_p_8_old_l = 0; mid_p_8_old_r = 0; if (sample_rate_play == AUD_SAMPRATE_8000) { playback_samplerate_ratio = 8 * 6; } else if (sample_rate_play == AUD_SAMPRATE_16000) { playback_samplerate_ratio = 8 * 3; } else if ((sample_rate_play == AUD_SAMPRATE_44100) || (sample_rate_play == AUD_SAMPRATE_48000) || (sample_rate_play == AUD_SAMPRATE_50781)) { playback_samplerate_ratio = 8; } else if ((sample_rate_play == AUD_SAMPRATE_88200) || (sample_rate_play == AUD_SAMPRATE_96000)) { playback_samplerate_ratio = 4; } else if ((sample_rate_play == AUD_SAMPRATE_176400) || (sample_rate_play == AUD_SAMPRATE_192000)) { playback_samplerate_ratio = 2; } else if (sample_rate_play == AUD_SAMPRATE_384000) { playback_samplerate_ratio = 1; } else { playback_samplerate_ratio = 1; ASSERT(false, "Music cancel can't support playback sample rate:%d", sample_rate_play); } anc_mc_run_init((sample_rate_play * playback_samplerate_ratio) / 8); stream_cfg.data_size = playback_size * playback_samplerate_ratio; // TRACE(3,"[%s] sample_rate: %d, bits = %d", __func__, // stream_cfg.sample_rate, stream_cfg.bits); ret = af_stream_open(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, &stream_cfg); ASSERT(ret == 0, "af_stream_open playback failed: %d", ret); #endif } else { #if defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY) capture_size = calc_capture_size(sample_rate_cap); #endif update_capture_sync_info(); stream_cfg.bits = sample_size_to_enum_capture(sample_size_cap); stream_cfg.sample_rate = sample_rate_cap; stream_cfg.channel_num = chan_num_to_enum(CHAN_NUM_CAPTURE); #ifdef ANC_PROD_TEST stream_cfg.channel_map = anc_fb_mic_ch_l | anc_fb_mic_ch_r; #endif #ifdef USB_I2S_APP #if defined(USB_I2S_ID) && (USB_I2S_ID == 0) stream_cfg.device = AUD_STREAM_USE_I2S0_MASTER; #else stream_cfg.device = AUD_STREAM_USE_I2S1_MASTER; #endif #else stream_cfg.device = AUD_STREAM_USE_INT_CODEC; #endif stream_cfg.vol = capture_vol; stream_cfg.handler = usb_audio_data_capture; #if !defined(USB_AUDIO_SPEECH) && defined(BTUSB_AUDIO_MODE) stream_cfg.io_path = AUD_INPUT_PATH_USBAUDIO; #else stream_cfg.io_path = AUD_INPUT_PATH_MAINMIC; #endif stream_cfg.data_ptr = capture_buf; stream_cfg.data_size = capture_size; // TRACE(4,"[%s] sample_rate: %d, bits = %d, ch_num = %d", __func__, // stream_cfg.sample_rate, stream_cfg.bits, stream_cfg.channel_num); ret = af_stream_open(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg); ASSERT(ret == 0, "af_stream_open catpure failed: %d", ret); } } if (user < AUDIO_STREAM_REQ_USER_QTY) { codec_stream_map[stream][AUDIO_STREAM_OPENED] |= (1 << user); } return ret; } static int usb_audio_close_codec_stream(enum AUD_STREAM_T stream, enum AUDIO_STREAM_REQ_USER_T user) { int ret = 0; TRACE(4, "%s: stream=%d user=%d map=0x%x", __FUNCTION__, stream, user, codec_stream_map[stream][AUDIO_STREAM_OPENED]); if (user < AUDIO_STREAM_REQ_USER_QTY) { codec_stream_map[stream][AUDIO_STREAM_OPENED] &= ~(1 << user); } if (user >= AUDIO_STREAM_REQ_USER_QTY || codec_stream_map[stream][AUDIO_STREAM_OPENED] == 0) { ret = af_stream_close(AUD_STREAM_ID_0, stream); #ifdef AUDIO_ANC_FB_MC if (stream == AUD_STREAM_PLAYBACK) { ret = af_stream_close(AUD_STREAM_ID_2, stream); } #endif } return ret; } static int usb_audio_open_eq(void) { int ret = 0; TRACE(4, "[%s] EQ: sample_rate_recv=%d, sample_rate_play=%d, sample_bits=%d", __func__, sample_rate_recv, sample_rate_play, sample_size_to_enum_playback(sample_size_play)); #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_IIR_EQ_PROCESS__) || defined(__HW_DAC_IIR_EQ_PROCESS__) enum AUD_BITS_T sample_bits = sample_size_to_enum_playback(sample_size_play); enum AUD_CHANNEL_NUM_T chan_num = chan_num_to_enum(CHAN_NUM_PLAYBACK); ret = audio_process_open(sample_rate_play, sample_bits, chan_num, playback_eq_size / 2, playback_eq_buf, playback_eq_size); // TRACE(1,"audio_process_open: %d", ret); #ifdef __SW_IIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_SW_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_SW_IIR, 0)); #endif #ifdef __HW_FIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_HW_FIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_FIR, 0)); #endif #ifdef __HW_DAC_IIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_HW_DAC_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_DAC_IIR, 0)); #endif #ifdef __HW_IIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_HW_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_IIR, 0)); #endif #endif eq_opened = 1; return ret; } static int usb_audio_close_eq(void) { int ret = 0; #if defined(__SW_IIR_EQ_PROCESS__) || defined(__HW_FIR_EQ_PROCESS__) || \ defined(__HW_IIR_EQ_PROCESS__) || defined(__HW_DAC_IIR_EQ_PROCESS__) ret = audio_process_close(); #endif eq_opened = 0; return ret; } static int usb_audio_start_codec_stream(enum AUD_STREAM_T stream, enum AUDIO_STREAM_REQ_USER_T user) { int ret = 0; TRACE(4, "%s: stream=%d user=%d map=0x%x", __FUNCTION__, stream, user, codec_stream_map[stream][AUDIO_STREAM_STARTED]); if (user >= AUDIO_STREAM_REQ_USER_QTY || codec_stream_map[stream][AUDIO_STREAM_STARTED] == 0) { reset_conflict(); if (stream == AUD_STREAM_PLAYBACK) { zero_mem32(playback_buf, playback_size); codec_play_valid = 0; usb_recv_init_rpos = 0; playback_pos = 0; playback_conflicted = 0; #ifdef USB_AUDIO_MULTIFUNC usb_recv2_init_rpos = 0; playback_conflicted2 = 0; #endif #ifdef DSD_SUPPORT if (codec_dsd_enabled) { #if defined(__HW_FIR_DSD_PROCESS__) uint8_t *dsd_buf; uint32_t dsd_size; // DoP format requirement dsd_size = playback_size * 16; ; dsd_buf = (uint8_t *)(HW_FIR_DSD_BUF_MID_ADDR - dsd_size / 2); dsd_open(sample_rate_play, AUD_BITS_24, AUD_CHANNEL_NUM_2, dsd_buf, dsd_size); #elif defined(CODEC_DSD) af_dsd_enable(); #endif } #endif usb_audio_open_eq(); } else { #if defined(CHIP_BEST1000) && defined(_DUAL_AUX_MIC_) damic_init(); init_amic_dc(); #endif #ifdef USB_AUDIO_SPEECH app_overlay_select(APP_OVERLAY_HFP); speech_process_init(sample_rate_cap, CHAN_NUM_CAPTURE, sample_size_to_enum_playback(sample_size_cap), sample_rate_play, CHAN_NUM_PLAYBACK, sample_size_to_enum_playback(sample_size_play), 16, 16, CHAN_NUM_SEND, CHAN_NUM_RECV); #endif codec_cap_valid = 0; usb_send_init_wpos = 0; capture_pos = 0; capture_conflicted = 0; } // Tune rate according to the newest sync ratio info usb_audio_cmd_tune_rate(stream); ret = af_stream_start(AUD_STREAM_ID_0, stream); ASSERT(ret == 0, "af_stream_start %d failed: %d", stream, ret); if (stream == AUD_STREAM_PLAYBACK) { #ifdef AUDIO_ANC_FB_MC ret = af_stream_start(AUD_STREAM_ID_2, stream); ASSERT(ret == 0, "af_stream_start %d failed: %d", stream, ret); #endif } else { codec_cap_start_time = hal_sys_timer_get(); } } if (user < AUDIO_STREAM_REQ_USER_QTY) { codec_stream_map[stream][AUDIO_STREAM_STARTED] |= (1 << user); } return ret; } static int usb_audio_stop_codec_stream(enum AUD_STREAM_T stream, enum AUDIO_STREAM_REQ_USER_T user) { int ret = 0; TRACE(4, "%s: stream=%d user=%d map=0x%x", __FUNCTION__, stream, user, codec_stream_map[stream][AUDIO_STREAM_STARTED]); if (user < AUDIO_STREAM_REQ_USER_QTY) { codec_stream_map[stream][AUDIO_STREAM_STARTED] &= ~(1 << user); } if (user >= AUDIO_STREAM_REQ_USER_QTY || codec_stream_map[stream][AUDIO_STREAM_STARTED] == 0) { ret = af_stream_stop(AUD_STREAM_ID_0, stream); if (stream == AUD_STREAM_PLAYBACK) { #ifdef AUDIO_ANC_FB_MC ret = af_stream_stop(AUD_STREAM_ID_2, stream); #endif #ifdef DSD_SUPPORT if (codec_dsd_enabled) { #if defined(__HW_FIR_DSD_PROCESS__) dsd_close(); #elif defined(CODEC_DSD) af_dsd_disable(); #endif } #endif usb_audio_close_eq(); } else { #if defined(CHIP_BEST1000) && defined(_DUAL_AUX_MIC_) damic_deinit(); #endif #ifdef USB_AUDIO_SPEECH speech_process_deinit(); app_overlay_unloadall(); #endif } } return ret; } static int usb_audio_start_usb_stream(enum AUD_STREAM_T stream) { int ret; reset_conflict(); if (stream == AUD_STREAM_PLAYBACK) { usb_audio_sync_reset(&playback_info); usb_recv_valid = 0; #ifdef USB_AUDIO_MULTIFUNC if (recv2_state == AUDIO_ITF_STATE_STOPPED) #endif { usb_recv_seq++; } usb_recv_rpos = 0; usb_recv_wpos = usb_recv_size / 2; zero_mem32(usb_recv_buf, usb_recv_size); usb_recv_err_cnt = 0; #ifdef DSD_SUPPORT usb_dsd_enabled = false; usb_dsd_cont_cnt = 0; #endif ret = usb_audio_start_recv(usb_recv_buf, usb_recv_wpos, usb_recv_size); if (ret == 1) { TRACE(0, "usb_audio_start_recv failed: usb not configured"); } else { ASSERT(ret == 0, "usb_audio_start_recv failed: %d", ret); } } else { #ifndef UAUD_SYNC_STREAM_TARGET if (recv_state == AUDIO_ITF_STATE_STOPPED) #endif { usb_audio_sync_reset(&capture_info); } usb_send_valid = 0; usb_send_seq++; usb_send_rpos = usb_send_size / 2; usb_send_wpos = 0; zero_mem32(usb_send_buf, usb_send_size); usb_send_err_cnt = 0; ret = usb_audio_start_send(usb_send_buf, usb_send_rpos, usb_send_size); if (ret == 1) { TRACE(0, "usb_audio_start_send failed: usb not configured"); } else { ASSERT(ret == 0, "usb_audio_start_send failed: %d", ret); } } return ret; } static int usb_audio_stop_usb_stream(enum AUD_STREAM_T stream) { if (stream == AUD_STREAM_PLAYBACK) { usb_audio_stop_recv(); #ifdef DSD_SUPPORT usb_dsd_enabled = false; #endif usb_audio_sync_reset(&playback_info); } else { usb_audio_stop_send(); #ifndef UAUD_SYNC_STREAM_TARGET if (recv_state == AUDIO_ITF_STATE_STOPPED) #endif { usb_audio_sync_reset(&capture_info); } } return 0; } static void usb_audio_set_codec_volume(enum AUD_STREAM_T stream, uint8_t vol) { struct AF_STREAM_CONFIG_T *cfg; uint8_t POSSIBLY_UNUSED old_vol; uint32_t ret; ret = af_stream_get_cfg(AUD_STREAM_ID_0, stream, &cfg, true); if (ret == 0) { old_vol = cfg->vol; if (old_vol != vol) { cfg->vol = vol; af_stream_setup(AUD_STREAM_ID_0, stream, cfg); } } #ifdef AUDIO_ANC_FB_MC if (stream == AUD_STREAM_PLAYBACK) { ret = af_stream_get_cfg(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, &cfg, true); if (ret == 0) { if (cfg->vol != vol) { cfg->vol = vol; af_stream_setup(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, cfg); } } } #endif } static void usb_audio_enqueue_cmd(uint32_t data) { int ret; uint32_t mark; ret = safe_queue_put(&cmd_queue, data); ASSERT(ret == 0 || safe_queue_dump(&cmd_queue), "%s: cmd queue overflow", __FUNCTION__); hal_cpu_wake_lock(USB_AUDIO_CPU_WAKE_USER); mark = safe_queue_watermark(&cmd_queue); if (mark > cmd_watermark) { cmd_watermark = mark; TRACE(2, "%s: new watermark %u", __FUNCTION__, mark); } #ifdef BT_USB_AUDIO_DUAL_MODE if (enqueue_cmd_cb) { enqueue_cmd_cb(data); } #endif } #ifdef BT_USB_AUDIO_DUAL_MODE void usb_audio_set_enqueue_cmd_callback(USB_AUDIO_ENQUEUE_CMD_CALLBACK cb) { enqueue_cmd_cb = cb; } #endif static void enqueue_unique_cmd_with_opp(enum AUDIO_CMD_T cmd, uint8_t seq, uint8_t arg, enum AUDIO_CMD_T oppsite_cmd) { uint32_t last[3]; uint32_t lock; bool dup = false; lock = int_lock(); if (safe_queue_peek(&cmd_queue, -1, &last[0]) == 0 && safe_queue_peek(&cmd_queue, -2, &last[1]) == 0 && safe_queue_peek(&cmd_queue, -3, &last[2]) == 0) { if (EXTRACT_CMD(last[0]) == cmd) { dup = true; safe_queue_pop(&cmd_queue, NULL); } else if (EXTRACT_CMD(last[0]) == oppsite_cmd && EXTRACT_CMD(last[1]) == cmd && EXTRACT_CMD(last[2]) == oppsite_cmd) { dup = true; safe_queue_pop(&cmd_queue, NULL); safe_queue_pop(&cmd_queue, NULL); } } int_unlock(lock); usb_audio_enqueue_cmd(MAKE_QUEUE_DATA(cmd, seq, arg)); if (dup) { TRACE(2, "%s: Remove old duplicate cmd %d", __FUNCTION__, cmd); } } static void enqueue_unique_cmd_arg(enum AUDIO_CMD_T cmd, uint8_t seq, uint8_t arg) { uint32_t last; uint32_t cur; uint32_t lock; bool enqueue = true; cur = MAKE_QUEUE_DATA(cmd, seq, arg); lock = int_lock(); if (safe_queue_peek(&cmd_queue, -1, &last) == 0) { if (last == cur) { enqueue = false; } } int_unlock(lock); if (enqueue) { usb_audio_enqueue_cmd(cur); } else { TRACE(2, "%s: Skip duplicate cmd %d", __FUNCTION__, cmd); } } static void enqueue_unique_cmd(enum AUDIO_CMD_T cmd) { enqueue_unique_cmd_arg(cmd, 0, 0); } static void usb_audio_playback_start(enum USB_AUDIO_ITF_CMD_T cmd) { if (cmd == USB_AUDIO_ITF_STOP) { // Stop the stream right now if (recv_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STOPPED; } #ifdef USB_AUDIO_DYN_CFG playback_itf_set = 0; #ifdef USB_AUDIO_UAC2 enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_PLAY, usb_recv_seq, 0, AUDIO_CMD_START_PLAY); #else enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_PLAY, usb_recv_seq, 0, AUDIO_CMD_SET_RECV_RATE); #endif #else #ifdef USB_AUDIO_MULTIFUNC if (recv2_state == AUDIO_ITF_STATE_STARTED) { return; } #endif enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_PLAY, usb_recv_seq, 0, AUDIO_CMD_START_PLAY); #endif } else { #ifdef USB_AUDIO_DYN_CFG if (cmd == USB_AUDIO_ITF_START_16BIT) { new_sample_size_recv = 2; } else if (cmd == USB_AUDIO_ITF_START_24BIT) { new_sample_size_recv = 3; } else { new_sample_size_recv = 4; } playback_itf_set = 1; // Some host applications will not stop current stream before changing // sample size if (recv_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STOPPED; } #ifdef USB_AUDIO_UAC2 #ifdef KEEP_SAME_LATENCY usb_recv_size = calc_usb_recv_size(new_sample_rate_recv, new_sample_size_recv); TRACE(2, "%s: Set usb_recv_size=%u", __FUNCTION__, usb_recv_size); #endif usb_audio_start_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STARTED; enqueue_unique_cmd_with_opp(AUDIO_CMD_START_PLAY, usb_recv_seq, 0, AUDIO_CMD_STOP_PLAY); #else // Wait for sampling freq ctrl msg to start the stream #endif return; #else if (recv_state == AUDIO_ITF_STATE_STOPPED) { usb_audio_start_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STARTED; } #ifdef USB_AUDIO_MULTIFUNC if (recv2_state == AUDIO_ITF_STATE_STARTED) { return; } #endif enqueue_unique_cmd_with_opp(AUDIO_CMD_START_PLAY, usb_recv_seq, 0, AUDIO_CMD_STOP_PLAY); #endif } } static void usb_audio_capture_start(enum USB_AUDIO_ITF_CMD_T cmd) { if (cmd == USB_AUDIO_ITF_STOP) { // Stop the stream right now if (send_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STOPPED; } #ifdef USB_AUDIO_DYN_CFG capture_itf_set = 0; #ifdef USB_AUDIO_UAC2 enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_CAPTURE, usb_send_seq, 0, AUDIO_CMD_START_CAPTURE); #else enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_CAPTURE, usb_send_seq, 0, AUDIO_CMD_SET_SEND_RATE); #endif #else enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_CAPTURE, usb_send_seq, 0, AUDIO_CMD_START_CAPTURE); #endif } else { #ifdef USB_AUDIO_DYN_CFG capture_itf_set = 1; // Some host applications will not stop current stream before changing // sample size if (send_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STOPPED; } #ifdef USB_AUDIO_UAC2 usb_audio_start_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STARTED; enqueue_unique_cmd_with_opp(AUDIO_CMD_START_CAPTURE, usb_send_seq, 0, AUDIO_CMD_STOP_CAPTURE); #else // Wait for sampling freq ctrl msg to start the stream #endif return; #else if (send_state == AUDIO_ITF_STATE_STOPPED) { usb_audio_start_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STARTED; } enqueue_unique_cmd_with_opp(AUDIO_CMD_START_CAPTURE, usb_send_seq, 0, AUDIO_CMD_STOP_CAPTURE); #endif } } static void usb_audio_mute_control(uint32_t mute) { TRACE(1, "MUTE CTRL: %u", mute); new_mute_state = mute; #ifdef USB_AUDIO_MULTIFUNC if (mute) { new_playback_coef = 0; } else { new_playback_coef = playback_gain_to_float(new_playback_vol); } #endif usb_audio_enqueue_cmd(AUDIO_CMD_MUTE_CTRL); } static void usb_audio_cap_mute_control(uint32_t mute) { TRACE(1, "CAP MUTE CTRL: %u", mute); new_cap_mute_state = mute; usb_audio_enqueue_cmd(AUDIO_CMD_CAP_MUTE_CTRL); } static void usb_audio_vol_control(uint32_t percent) { if (percent >= 100) { new_playback_vol = MAX_VOLUME_VAL; } else { new_playback_vol = MIN_VOLUME_VAL + (percent * (MAX_VOLUME_VAL - MIN_VOLUME_VAL) + 50) / 100; } TRACE(2, "VOL CTRL: percent=%u new_playback_vol=%u", percent, new_playback_vol); #ifdef USB_AUDIO_MULTIFUNC new_playback_coef = playback_gain_to_float(new_playback_vol); #else usb_audio_enqueue_cmd(AUDIO_CMD_SET_VOLUME); #endif } static void usb_audio_cap_vol_control(uint32_t percent) { if (percent >= 100) { new_capture_vol = MAX_CAP_VOLUME_VAL; } else { new_capture_vol = MIN_CAP_VOLUME_VAL + (percent * (MAX_CAP_VOLUME_VAL - MIN_CAP_VOLUME_VAL) + 50) / 100; } TRACE(2, "CAP VOL CTRL: percent=%u new_capture_vol=%u", percent, new_capture_vol); usb_audio_enqueue_cmd(AUDIO_CMD_SET_CAP_VOLUME); } static uint32_t usb_audio_get_vol_percent(void) { if (new_playback_vol >= MAX_VOLUME_VAL) { return 100; } else if (new_playback_vol <= MIN_VOLUME_VAL) { return 0; } else { return ((new_playback_vol - MIN_VOLUME_VAL) * 100 + (MAX_VOLUME_VAL - MIN_VOLUME_VAL) / 2) / (MAX_VOLUME_VAL - MIN_VOLUME_VAL); } } static uint32_t usb_audio_get_cap_vol_percent(void) { if (new_capture_vol >= MAX_CAP_VOLUME_VAL) { return 100; } else if (new_capture_vol <= MIN_CAP_VOLUME_VAL) { return 0; } else { return ((new_capture_vol - MIN_CAP_VOLUME_VAL) * 100 + (MAX_CAP_VOLUME_VAL - MIN_CAP_VOLUME_VAL) / 2) / (MAX_CAP_VOLUME_VAL - MIN_CAP_VOLUME_VAL); } } static void usb_audio_tune_rate(enum AUD_STREAM_T stream, float ratio) { bool update_play, update_cap; update_play = true; update_cap = false; #if defined(__AUDIO_RESAMPLE__) && defined(PLL_TUNE_SAMPLE_RATE) #ifdef UAUD_SYNC_STREAM_TARGET if (stream == AUD_STREAM_PLAYBACK) { update_play = true; update_cap = false; } else { update_play = false; update_cap = true; } #else update_play = true; update_cap = true; #endif #endif if (update_play) { rate_tune_ratio[AUD_STREAM_PLAYBACK] = rate_tune_ratio[AUD_STREAM_PLAYBACK] + ratio + rate_tune_ratio[AUD_STREAM_PLAYBACK] * ratio; } if (update_cap) { rate_tune_ratio[AUD_STREAM_CAPTURE] = rate_tune_ratio[AUD_STREAM_CAPTURE] + ratio + rate_tune_ratio[AUD_STREAM_CAPTURE] * ratio; } TRACE(4, "%s[%u]: ratio=%d resample_ratio=%d", __FUNCTION__, stream, FLOAT_TO_PPB_INT(ratio), update_cap ? FLOAT_TO_PPB_INT(rate_tune_ratio[stream]) : FLOAT_TO_PPB_INT(rate_tune_ratio[AUD_STREAM_PLAYBACK])); enqueue_unique_cmd_arg(AUDIO_CMD_TUNE_RATE, 0, stream); } static void usb_audio_data_recv_handler(const struct USB_AUDIO_XFER_INFO_T *info) { const uint8_t *data; uint32_t size; uint32_t old_wpos, new_wpos, wpos_boundary, rpos; uint32_t old_play_pos = 0; uint32_t play_pos; uint32_t lock; int conflicted; uint32_t recv_samp, play_samp; uint32_t cur_time; cur_time = hal_sys_timer_get(); last_usb_recv_time = cur_time; data = info->data; size = info->size; if (info->cur_compl_err || info->next_xfer_err) { if (usb_recv_err_cnt == 0) { usb_recv_err_cnt++; usb_recv_ok_cnt = 0; last_usb_recv_err_time = cur_time; } else { usb_recv_err_cnt++; } } else { if (usb_recv_err_cnt) { usb_recv_ok_cnt++; } } if (usb_recv_err_cnt && cur_time - last_usb_recv_err_time >= USB_XFER_ERR_REPORT_INTERVAL) { if (info->cur_compl_err || info->next_xfer_err) { TRACE(2, "recv: ERROR: cur_err=%d next_err=%d", info->cur_compl_err, info->next_xfer_err); } TRACE(3, "recv: ERROR-CNT: err=%u ok=%u in %u ms", usb_recv_err_cnt, usb_recv_ok_cnt, TICKS_TO_MS(USB_XFER_ERR_REPORT_INTERVAL)); usb_recv_err_cnt = 0; } if (usb_recv_buf <= data && data <= usb_recv_buf + usb_recv_size) { if (data != usb_recv_buf + usb_recv_wpos) { TRACE( 3, "recv: WARNING: Invalid wpos=0x%x data=%p recv_buf=%p. IRQ missing?", usb_recv_wpos, data, usb_recv_buf); usb_recv_wpos = data - usb_recv_buf; } } old_wpos = usb_recv_wpos; new_wpos = old_wpos + size; if (new_wpos >= usb_recv_size) { new_wpos -= usb_recv_size; } if (recv_state == AUDIO_ITF_STATE_STOPPED || size == 0 || // rx paused 0) { usb_recv_valid = 0; } else { if (info->cur_compl_err == 0) { usb_recv_valid = 1; } } if (usb_recv_valid == 0 || usb_recv_init_rpos == 0 || codec_config_lock || codec_play_seq != usb_recv_seq || codec_play_valid == 0 || playback_state == AUDIO_ITF_STATE_STOPPED || 0) { usb_recv_wpos = new_wpos; return; } conflicted = 0; lock = int_lock(); if (playback_conflicted) { playback_conflicted = 0; rpos = 0; // Avoid compiler warnings conflicted = 1; } else { rpos = usb_recv_rpos; old_play_pos = playback_pos; play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); } int_unlock(lock); if (conflicted == 0) { if (info->pool_enabled) { // USBC will write to memory pool. wpos_boundary = new_wpos; } else { // USBC will write to new_wpos directly, so the buffer [new_wpos, new_wpos // + info->next_size) must be protected too. wpos_boundary = new_wpos + info->next_size; if (wpos_boundary >= usb_recv_size) { wpos_boundary -= usb_recv_size; } } if (old_wpos <= rpos) { if (wpos_boundary < old_wpos || rpos < wpos_boundary) { conflicted = 1; } } else { if (rpos < wpos_boundary && wpos_boundary < old_wpos) { conflicted = 1; } } if (conflicted) { uint32_t reset_len = usb_recv_size / 2; uint32_t saved_old_wpos = old_wpos; // Reset write position old_wpos = rpos + reset_len; if (old_wpos >= usb_recv_size) { old_wpos -= usb_recv_size; } new_wpos = old_wpos + size; if (new_wpos >= usb_recv_size) { new_wpos -= usb_recv_size; } #if 0 usb_audio_stop_recv(); usb_audio_start_recv(usb_recv_buf, new_wpos, usb_recv_size); #else usb_audio_set_recv_pos(new_wpos); #endif TRACE(4, "recv: Error: wpos=%u goes beyond rpos=%u with len=%u. Reset to %u", saved_old_wpos, rpos, size, old_wpos); } record_conflict(conflicted); } usb_recv_wpos = new_wpos; #if (VERBOSE_TRACE & (1 << 5)) { int hw_play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); TRACE_TIME(5, "recv: wpos=%u size=%u rpos=%u playback_pos=%u hw_play_pos=%d", old_wpos, size, rpos, playback_pos, hw_play_pos); } #endif if (conflicted) { usb_audio_sync_reset(&playback_info); return; } if (usb_recv_buf <= data && data <= usb_recv_buf + usb_recv_size) { recv_samp = byte_to_samp_recv(new_wpos); } else { recv_samp = -1; } if ((int)play_pos >= 0) { if (play_pos >= playback_size) { play_pos = 0; } // Count the bytes of data waiting to play in the codec buffer uint32_t bytes_to_play; if (old_play_pos <= play_pos) { bytes_to_play = playback_size + old_play_pos - play_pos; } else { bytes_to_play = old_play_pos - play_pos; } uint32_t usb_bytes_to_play; usb_bytes_to_play = playback_to_recv_len(bytes_to_play); if (rpos >= usb_bytes_to_play) { play_pos = rpos - usb_bytes_to_play; } else { play_pos = usb_recv_size + rpos - usb_bytes_to_play; } play_samp = byte_to_samp_recv(play_pos); } else { play_samp = -1; } if (recv_samp != -1 && play_samp != -1) { enum UAUD_SYNC_RET_T ret; float ratio; ret = usb_audio_sync(play_samp, recv_samp, &playback_info, &ratio); if (ret == UAUD_SYNC_START) { usb_audio_tune_rate(AUD_STREAM_PLAYBACK, ratio); } } else { // TRACE(2,"recv_hdlr: recv_samp=0x%08x play_samp=0x%08x", recv_samp, // play_samp); } #ifdef DSD_SUPPORT if (sample_size_recv == 3 && (sample_rate_recv == 176400 || sample_rate_recv == 352800)) { // First DoP solution marks static const uint8_t pattern[2] = { 0x05, 0xFA, }; // Second DoP solution marks -- not supported yet // static const uint8_t pattern2[2] = { 0x06, 0xF9, }; static const uint16_t dsd_detect_thresh = 32; uint8_t idx; const uint8_t *dsd, *dsd_end, *dsd_end2; bool dsd_valid = true; dsd = data + 2; dsd_end = data + size; dsd_end2 = usb_recv_buf + usb_recv_size; if (dsd_end <= dsd_end2) { dsd_end2 = NULL; } else { dsd_end = dsd_end2; dsd_end2 = data + size - usb_recv_size; } if (*dsd == pattern[0]) { idx = 0; } else { idx = 1; } _check_dsd: while (dsd < dsd_end) { if (*dsd == pattern[idx]) { #if (CHAN_NUM_RECV == 2) dsd += 3; if (dsd >= dsd_end || *dsd != pattern[idx]) { dsd_valid = false; break; } #endif if (usb_dsd_cont_cnt < dsd_detect_thresh) { usb_dsd_cont_cnt += CHAN_NUM_RECV; } idx = !idx; dsd += 3; } else { dsd_valid = false; break; } } if (dsd_valid && dsd_end2) { dsd = usb_recv_buf + 2; dsd_end = dsd_end2; dsd_end2 = NULL; goto _check_dsd; } if (dsd_valid && usb_dsd_cont_cnt < dsd_detect_thresh) { dsd_valid = false; } if (!dsd_valid) { usb_dsd_cont_cnt = 0; } if (dsd_valid != usb_dsd_enabled) { usb_dsd_enabled = dsd_valid; enqueue_unique_cmd(AUDIO_CMD_SET_DSD_CFG); } } #endif } static void usb_audio_data_send_handler(const struct USB_AUDIO_XFER_INFO_T *info) { const uint8_t *data; uint32_t size; uint32_t old_rpos, new_rpos, rpos_boundary, wpos; uint32_t old_cap_pos = 0; uint32_t cap_pos; uint32_t lock; int conflicted; uint32_t send_samp, cap_samp; uint32_t cur_time; cur_time = hal_sys_timer_get(); last_usb_send_time = cur_time; data = info->data; size = info->size; if (info->cur_compl_err || info->next_xfer_err) { if (usb_send_err_cnt == 0) { usb_send_err_cnt++; usb_send_ok_cnt = 0; last_usb_send_err_time = cur_time; } else { usb_send_err_cnt++; } } else { if (usb_send_err_cnt) { usb_send_ok_cnt++; } } if (usb_send_err_cnt && cur_time - last_usb_send_err_time >= USB_XFER_ERR_REPORT_INTERVAL) { if (info->cur_compl_err || info->next_xfer_err) { TRACE(2, "send: ERROR: cur_err=%d next_err=%d", info->cur_compl_err, info->next_xfer_err); } TRACE(3, "send: ERROR-CNT: err=%u ok=%u in %u ms", usb_send_err_cnt, usb_send_ok_cnt, TICKS_TO_MS(USB_XFER_ERR_REPORT_INTERVAL)); usb_send_err_cnt = 0; } if (info->pool_enabled) { // The buffer [data, size) has been sent completely, and // the buffer [data + size, data + size + info->next_size) has been copied // to memory pool. Make usb_send_rpos point to the pending send buffer data += size; if (data >= usb_send_buf + usb_send_size) { data -= usb_send_size; } size = info->next_size; } if (usb_send_buf <= data && data <= usb_send_buf + usb_send_size) { if (data != usb_send_buf + usb_send_rpos) { if (usb_send_valid == 0 && info->pool_enabled && info->data != usb_send_buf + usb_send_rpos) { TRACE(3, "send: WARNING: Invalid rpos=0x%x data=%p send_buf=%p. IRQ " "missing?", usb_send_rpos, data, usb_send_buf); } usb_send_rpos = data - usb_send_buf; } } old_rpos = usb_send_rpos; new_rpos = old_rpos + size; if (new_rpos >= usb_send_size) { new_rpos -= usb_send_size; } if (send_state == AUDIO_ITF_STATE_STOPPED || size == 0 || // tx paused 0) { usb_send_valid = 0; } else { if (info->cur_compl_err == 0) { usb_send_valid = 1; } } if (usb_send_valid == 0 || usb_send_init_wpos == 0 || codec_config_lock || codec_cap_seq != usb_send_seq || codec_cap_valid == 0 || capture_state == AUDIO_ITF_STATE_STOPPED || 0) { usb_send_rpos = new_rpos; if (usb_send_valid) { // Zero the send buffer next to the part being sent by USB h/w if (info->pool_enabled) { uint32_t clr_len; clr_len = samp_to_byte_send(SAMP_RATE_TO_FRAME_SIZE(sample_rate_send)); if (usb_send_rpos + clr_len <= usb_send_size) { zero_mem16(usb_send_buf + usb_send_rpos, clr_len); } else { zero_mem16(usb_send_buf + usb_send_rpos, usb_send_size - usb_send_rpos); zero_mem16(usb_send_buf, clr_len - (usb_send_size - usb_send_rpos)); } } else { // If no pool is enabled, the send pkt size is a fixed value, and // the send buffer size is a integral multiple of the send pkt size if (usb_send_rpos + size + size <= usb_send_size) { zero_mem32(usb_send_buf + usb_send_rpos + size, size); } else { zero_mem32(usb_send_buf, size); } } } return; } conflicted = 0; lock = int_lock(); if (capture_conflicted) { capture_conflicted = 0; wpos = 0; // Avoid compiler warnings conflicted = 1; } else { wpos = usb_send_wpos; old_cap_pos = capture_pos; cap_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE); } int_unlock(lock); if (conflicted == 0) { if (info->pool_enabled) { // old_rpos points to the pending send buffer, which has been copied to // memory pool. USBC will read from memory pool. rpos_boundary = new_rpos; } else { // old_rpos points to the buffer just sent completely. // USBC will read from new_rpos directly, so the buffer [new_rpos, // new_rpos + info->next_size) must be protected too. rpos_boundary = new_rpos + info->next_size; if (rpos_boundary >= usb_recv_size) { rpos_boundary -= usb_recv_size; } } if (old_rpos <= wpos) { if (new_rpos < old_rpos || wpos < new_rpos) { conflicted = 1; } } else { if (wpos < new_rpos && new_rpos < old_rpos) { conflicted = 1; } } if (conflicted) { uint32_t reset_len = usb_send_size / 2; uint32_t saved_old_rpos = old_rpos; // Reset read position old_rpos = wpos + reset_len; if (old_rpos >= usb_send_size) { old_rpos -= usb_send_size; } new_rpos = old_rpos + size; if (new_rpos >= usb_send_size) { new_rpos -= usb_send_size; } #if 0 usb_audio_stop_send(); usb_audio_start_send(usb_send_buf, new_rpos, usb_send_size); #else usb_audio_set_send_pos(new_rpos); #endif TRACE(4, "send: Error: rpos=%u goes beyond wpos=%u with len=%u. Reset to %u", saved_old_rpos, wpos, size, old_rpos); } record_conflict(conflicted); } usb_send_rpos = new_rpos; #if (VERBOSE_TRACE & (1 << 6)) TRACE_TIME(3, "send: rpos=%u size=%u wpos=%u", old_rpos, size, wpos); #endif if (conflicted) { usb_audio_sync_reset(&capture_info); return; } #ifndef UAUD_SYNC_STREAM_TARGET // Recv takes precedence if (recv_state == AUDIO_ITF_STATE_STARTED) { return; } #endif if (usb_send_buf <= data && data <= usb_send_buf + usb_send_size) { send_samp = byte_to_samp_send(new_rpos); } else { send_samp = -1; } if ((int)cap_pos >= 0) { if (cap_pos >= capture_size) { cap_pos = 0; } // Count the bytes of data newly captured in the codec buffer uint32_t bytes_cap; if (old_cap_pos <= cap_pos) { bytes_cap = cap_pos - old_cap_pos; } else { bytes_cap = capture_size + cap_pos - old_cap_pos; } uint32_t usb_bytes_cap; usb_bytes_cap = capture_to_send_len(bytes_cap); cap_pos = wpos + usb_bytes_cap; if (cap_pos >= usb_send_size) { cap_pos -= usb_send_size; } cap_samp = byte_to_samp_send(cap_pos); } else { cap_samp = -1; } if (send_samp != -1 && cap_samp != -1) { enum UAUD_SYNC_RET_T ret; float ratio; ret = usb_audio_sync(cap_samp, send_samp, &capture_info, &ratio); if (ret == UAUD_SYNC_START) { usb_audio_tune_rate(AUD_STREAM_CAPTURE, ratio); } } else { // TRACE(2,"send_hdlr: send_samp=0x%08x cap_samp=0x%08x", send_samp, // cap_samp); } } #ifdef USB_AUDIO_MULTIFUNC static float playback_gain_to_float(uint32_t level) { int32_t db; if (level > MAX_VOLUME_VAL || level < MIN_VOLUME_VAL) { return 0; } db = codec_dac_vol[level].sdac_volume; if (db <= USB_AUDIO_MIN_DBVAL) { return 0; } return db_to_float(db); } static void usb_audio_playback2_start(enum USB_AUDIO_ITF_CMD_T cmd) { if (cmd == USB_AUDIO_ITF_STOP) { // Stop the stream right now if (recv2_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_recv2(); if (recv_state == AUDIO_ITF_STATE_STOPPED && send_state == AUDIO_ITF_STATE_STOPPED) { usb_audio_sync_reset(&playback_info); } recv2_state = AUDIO_ITF_STATE_STOPPED; } if (recv_state == AUDIO_ITF_STATE_STARTED) { return; } enqueue_unique_cmd_with_opp(AUDIO_CMD_STOP_PLAY, usb_recv_seq, 0, AUDIO_CMD_START_PLAY); } else { if (recv2_state == AUDIO_ITF_STATE_STOPPED) { int ret; reset_conflict(); if (recv_state == AUDIO_ITF_STATE_STOPPED && send_state == AUDIO_ITF_STATE_STOPPED) { usb_audio_sync_reset(&playback_info); } usb_recv2_valid = 0; if (recv_state == AUDIO_ITF_STATE_STOPPED) { usb_recv_seq++; } usb_recv2_rpos = 0; usb_recv2_wpos = usb_recv_size / 2; zero_mem32(usb_recv2_buf, usb_recv2_size); usb_recv2_err_cnt = 0; ret = usb_audio_start_recv2(usb_recv2_buf, usb_recv2_wpos, usb_recv2_size); if (ret == 1) { TRACE(0, "usb_audio_start_recv2 failed: usb not configured"); } else { ASSERT(ret == 0, "usb_audio_start_recv2 failed: %d", ret); } recv2_state = AUDIO_ITF_STATE_STARTED; } if (recv_state == AUDIO_ITF_STATE_STARTED) { return; } enqueue_unique_cmd_with_opp(AUDIO_CMD_START_PLAY, usb_recv_seq, 0, AUDIO_CMD_STOP_PLAY); } } static void usb_audio_mute2_control(uint32_t mute) { TRACE(1, "MUTE2 CTRL: %u", mute); new_mute2_state = mute; if (mute) { new_playback2_coef = 0; } else { new_playback2_coef = playback_gain_to_float(new_playback2_vol); } usb_audio_enqueue_cmd(AUDIO_CMD_MUTE_CTRL); } static void usb_audio_vol2_control(uint32_t percent) { if (percent >= 100) { new_playback2_vol = MAX_VOLUME_VAL; } else { new_playback2_vol = MIN_VOLUME_VAL + (percent * (MAX_VOLUME_VAL - MIN_VOLUME_VAL) + 50) / 100; } new_playback2_coef = playback_gain_to_float(new_playback2_vol); TRACE(2, "VOL2 CTRL: percent=%u new_playback_vol=%u", percent, new_playback2_vol); } static uint32_t usb_audio_get_vol2_percent(void) { if (new_playback2_vol >= MAX_VOLUME_VAL) { return 100; } else { return ((new_playback2_vol - MIN_VOLUME_VAL) * 100 + (MAX_VOLUME_VAL - MIN_VOLUME_VAL) / 2) / (MAX_VOLUME_VAL - MIN_VOLUME_VAL); } } static void usb_audio_data_recv2_handler(const struct USB_AUDIO_XFER_INFO_T *info) { const uint8_t *data; uint32_t size; uint32_t old_wpos, new_wpos, wpos_boundary, rpos; uint32_t old_play_pos = 0; uint32_t play_pos; uint32_t lock; int conflicted; uint32_t recv_samp, play_samp; uint32_t cur_time; cur_time = hal_sys_timer_get(); last_usb_recv_time = cur_time; data = info->data; size = info->size; if (info->cur_compl_err || info->next_xfer_err) { if (usb_recv2_err_cnt == 0) { usb_recv2_err_cnt++; usb_recv2_ok_cnt = 0; last_usb_recv2_err_time = cur_time; } else { usb_recv2_err_cnt++; } } else { if (usb_recv2_err_cnt) { usb_recv2_ok_cnt++; } } if (usb_recv2_err_cnt && cur_time - last_usb_recv2_err_time >= USB_XFER_ERR_REPORT_INTERVAL) { if (info->cur_compl_err || info->next_xfer_err) { TRACE(2, "recv2: ERROR: cur_err=%d next_err=%d", info->cur_compl_err, info->next_xfer_err); } TRACE(3, "recv2: ERROR-CNT: err=%u ok=%u in %u ms", usb_recv2_err_cnt, usb_recv2_ok_cnt, TICKS_TO_MS(USB_XFER_ERR_REPORT_INTERVAL)); usb_recv2_err_cnt = 0; } if (usb_recv2_buf <= data && data <= usb_recv2_buf + usb_recv2_size) { if (data != usb_recv2_buf + usb_recv2_wpos) { TRACE(3, "recv2: WARNING: Invalid wpos=0x%x data=%p recv2_buf=%p. IRQ " "missing?", usb_recv2_wpos, data, usb_recv2_buf); usb_recv2_wpos = data - usb_recv2_buf; } } old_wpos = usb_recv2_wpos; new_wpos = old_wpos + size; if (new_wpos >= usb_recv2_size) { new_wpos -= usb_recv2_size; } if (codec_config_lock || codec_play_seq != usb_recv_seq || codec_play_valid == 0 || playback_state == AUDIO_ITF_STATE_STOPPED || recv2_state == AUDIO_ITF_STATE_STOPPED || size == 0 || // rx paused 0) { usb_recv2_valid = 0; } else { if (info->cur_compl_err == 0) { usb_recv2_valid = 1; } } if (usb_recv2_valid == 0 || usb_recv2_init_rpos == 0) { usb_recv2_wpos = new_wpos; return; } conflicted = 0; lock = int_lock(); if (playback_conflicted2) { playback_conflicted2 = 0; rpos = 0; // Avoid compiler warnings conflicted = 1; } else { rpos = usb_recv2_rpos; old_play_pos = playback_pos; play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); } int_unlock(lock); if (conflicted == 0) { if (info->pool_enabled) { // USBC will write to memory pool. wpos_boundary = new_wpos; } else { // USBC will write to new_wpos directly, so the buffer [new_wpos, new_wpos // + info->next_size) must be protected too. wpos_boundary = new_wpos + info->next_size; if (wpos_boundary >= usb_recv2_size) { wpos_boundary -= usb_recv2_size; } } if (old_wpos <= rpos) { if (wpos_boundary < old_wpos || rpos < wpos_boundary) { conflicted = 1; } } else { if (rpos < wpos_boundary && wpos_boundary < old_wpos) { conflicted = 1; } } if (conflicted) { uint32_t reset_len = usb_recv2_size / 2; uint32_t saved_old_wpos = old_wpos; // Reset read position old_wpos = rpos + reset_len; if (old_wpos >= usb_recv2_size) { old_wpos -= usb_recv2_size; } new_wpos = old_wpos + size; if (new_wpos >= usb_recv2_size) { new_wpos -= usb_recv2_size; } #if 0 usb_audio_stop_recv(); usb_audio_start_recv(usb_recv2_buf, new_wpos, usb_recv2_size); #else usb_audio_set_recv2_pos(new_wpos); #endif TRACE( 4, "recv2: Error: wpos=%u goes beyond rpos=%u with len=%u. Reset to %u", saved_old_wpos, rpos, size, old_wpos); } record_conflict(conflicted); } usb_recv2_wpos = new_wpos; #if (VERBOSE_TRACE & (1 << 5)) { int hw_play_pos = af_stream_get_cur_dma_pos(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK); TRACE_TIME(5, "recv2: wpos=%u size=%u rpos=%u playback_pos=%u hw_play_pos=%d", old_wpos, size, rpos, playback_pos, hw_play_pos); } #endif if (conflicted) { usb_audio_sync_reset(&playback_info); return; } // Recv and send takes precedence if (recv_state == AUDIO_ITF_STATE_STARTED || send_state == AUDIO_ITF_STATE_STARTED) { return; } if (usb_recv2_buf <= data && data <= usb_recv2_buf + usb_recv2_size) { recv_samp = byte_to_samp_recv(new_wpos); } else { recv_samp = -1; } if ((int)play_pos >= 0) { if (play_pos >= playback_size) { play_pos = 0; } // Count the bytes of data waiting to play in the codec buffer uint32_t bytes_to_play; if (old_play_pos <= play_pos) { bytes_to_play = playback_size + old_play_pos - play_pos; } else { bytes_to_play = old_play_pos - play_pos; } uint32_t usb_bytes_to_play; usb_bytes_to_play = playback_to_recv_len(bytes_to_play); if (rpos >= usb_bytes_to_play) { play_pos = rpos - usb_bytes_to_play; } else { play_pos = usb_recv2_size + rpos - usb_bytes_to_play; } play_samp = byte_to_samp_recv(play_pos); } else { play_samp = -1; } if (recv_samp != -1 && play_samp != -1) { enum UAUD_SYNC_RET_T ret; float ratio; ret = usb_audio_sync(play_samp, recv_samp, &playback_info, &ratio); if (ret == UAUD_SYNC_START) { usb_audio_tune_rate(AUD_STREAM_PLAYBACK, ratio); } } else { // TRACE(2,"recv_hdlr: recv_samp=0x%08x play_samp=0x%08x", recv_samp, // play_samp); } } #endif static void usb_audio_reset_usb_stream_state(bool init) { if (init) { recv_state = AUDIO_ITF_STATE_STOPPED; send_state = AUDIO_ITF_STATE_STOPPED; #ifdef USB_AUDIO_DYN_CFG // Reset itf setting playback_itf_set = 0; capture_itf_set = 0; #endif // Reset mute and volume setting new_mute_state = 0; new_cap_mute_state = 0; new_playback_vol = AUDIO_OUTPUT_VOLUME_DEFAULT; if (new_playback_vol > MAX_VOLUME_VAL) { new_playback_vol = MAX_VOLUME_VAL; } else if (new_playback_vol < MIN_VOLUME_VAL) { new_playback_vol = MIN_VOLUME_VAL; } new_capture_vol = CODEC_SADC_VOL; if (new_capture_vol > MAX_CAP_VOLUME_VAL) { new_capture_vol = MAX_CAP_VOLUME_VAL; } else if (new_capture_vol < MIN_CAP_VOLUME_VAL) { new_capture_vol = MIN_CAP_VOLUME_VAL; } #ifdef USB_AUDIO_MULTIFUNC new_playback_coef = playback_gain_to_float(new_playback_vol); playback_coef = new_playback_coef; recv2_state = AUDIO_ITF_STATE_STOPPED; new_mute2_state = 0; new_playback2_vol = AUDIO_OUTPUT_VOLUME_DEFAULT; if (new_playback2_vol > MAX_VOLUME_VAL) { new_playback2_vol = MAX_VOLUME_VAL; } else if (new_playback2_vol < MIN_VOLUME_VAL) { new_playback2_vol = MIN_VOLUME_VAL; } new_playback2_coef = playback_gain_to_float(new_playback2_vol); playback2_coef = new_playback2_coef; #endif } else { if (recv_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STOPPED; } if (send_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STOPPED; } #ifdef USB_AUDIO_MULTIFUNC if (recv2_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_recv2(); if (recv_state == AUDIO_ITF_STATE_STOPPED && send_state == AUDIO_ITF_STATE_STOPPED) { usb_audio_sync_reset(&playback_info); } recv2_state = AUDIO_ITF_STATE_STOPPED; } #endif // Keep old itf setting unless it is in init mode // Keep old mute and playback volume setting unless it is in init mode } } static void usb_audio_reset_codec_stream_state(bool init) { playback_state = AUDIO_ITF_STATE_STOPPED; capture_state = AUDIO_ITF_STATE_STOPPED; #ifndef USB_AUDIO_MULTIFUNC playback_vol = new_playback_vol; #endif capture_vol = new_capture_vol; playback_paused = 0; playback_conflicted = 0; #ifdef USB_AUDIO_MULTIFUNC playback_conflicted2 = 0; #endif capture_conflicted = 0; // Keep old mute setting unless it is in init mode if (init) { #ifdef PERF_TEST_POWER_KEY perft_power_type = 0; af_codec_set_perf_test_power(perft_power_type); #endif #ifdef PA_ON_OFF_KEY if (pa_on_off_muted) { pa_on_off_muted = false; if (mute_user_map == 0) { usb_audio_codec_unmute(CODEC_MUTE_USER_ALL); } } #endif if (mute_user_map) { mute_user_map = 0; usb_audio_codec_unmute(CODEC_MUTE_USER_ALL); } #if defined(NOISE_GATING) && defined(NOISE_REDUCTION) restore_noise_reduction_status(); #endif } } #ifdef USB_AUDIO_DYN_CFG static void usb_audio_set_recv_rate(enum AUD_SAMPRATE_T rate) { #ifndef USB_AUDIO_UAC2 if (playback_itf_set == 0) { TRACE(1, "\nWARNING: Set recv rate while itf not set: %d\n", rate); return; } #endif // Some host applications will not stop current stream before changing sample // rate if (recv_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STOPPED; } TRACE(3, "%s: Change recv sample rate from %u to %u", __FUNCTION__, sample_rate_recv, rate); new_sample_rate_recv = rate; #ifdef KEEP_SAME_LATENCY usb_recv_size = calc_usb_recv_size(new_sample_rate_recv, new_sample_size_recv); TRACE(2, "%s: Set usb_recv_size=%u", __FUNCTION__, usb_recv_size); #endif if (playback_itf_set) { usb_audio_start_usb_stream(AUD_STREAM_PLAYBACK); recv_state = AUDIO_ITF_STATE_STARTED; } #ifdef USB_AUDIO_UAC2 enqueue_unique_cmd_arg(AUDIO_CMD_SET_RECV_RATE, usb_recv_seq, 0); #else enqueue_unique_cmd_with_opp(AUDIO_CMD_SET_RECV_RATE, usb_recv_seq, 0, AUDIO_CMD_STOP_PLAY); #endif } static void usb_audio_set_send_rate(enum AUD_SAMPRATE_T rate) { #ifndef USB_AUDIO_UAC2 if (capture_itf_set == 0) { TRACE(1, "\nWARNING: Set send rate while itf not set: %d\n", rate); return; } #endif // Some host applications will not stop current stream before changing sample // rate if (send_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STOPPED; } TRACE(3, "%s: Change send sample rate from %u to %u", __FUNCTION__, sample_rate_send, rate); new_sample_rate_send = rate; #ifdef KEEP_SAME_LATENCY usb_send_size = calc_usb_send_size(new_sample_rate_send); TRACE(2, "%s: Set usb_send_size=%u", __FUNCTION__, usb_send_size); #endif if (capture_itf_set) { usb_audio_start_usb_stream(AUD_STREAM_CAPTURE); send_state = AUDIO_ITF_STATE_STARTED; } #ifdef USB_AUDIO_UAC2 enqueue_unique_cmd_arg(AUDIO_CMD_SET_SEND_RATE, usb_send_seq, 0); #else enqueue_unique_cmd_with_opp(AUDIO_CMD_SET_SEND_RATE, usb_send_seq, 0, AUDIO_CMD_STOP_CAPTURE); #endif } #endif static void usb_audio_state_control(enum USB_AUDIO_STATE_EVENT_T event, uint32_t param) { TRACE(3, "%s: %d (%u)", __FUNCTION__, event, param); if (event == USB_AUDIO_STATE_RESET || event == USB_AUDIO_STATE_DISCONNECT || event == USB_AUDIO_STATE_CONFIG) { usb_audio_reset_usb_stream_state(true); } else if (event == USB_AUDIO_STATE_SLEEP || event == USB_AUDIO_STATE_WAKEUP) { usb_audio_reset_usb_stream_state(false); } if (event == USB_AUDIO_STATE_RESET) { usb_audio_enqueue_cmd(AUDIO_CMD_USB_RESET); } else if (event == USB_AUDIO_STATE_DISCONNECT) { usb_audio_enqueue_cmd(AUDIO_CMD_USB_DISCONNECT); } else if (event == USB_AUDIO_STATE_CONFIG) { usb_audio_enqueue_cmd(AUDIO_CMD_USB_CONFIG); } else if (event == USB_AUDIO_STATE_SLEEP) { usb_audio_enqueue_cmd(AUDIO_CMD_USB_SLEEP); } else if (event == USB_AUDIO_STATE_WAKEUP) { usb_audio_enqueue_cmd(AUDIO_CMD_USB_WAKEUP); } else if (event == USB_AUDIO_STATE_RECV_PAUSE || event == USB_AUDIO_STATE_RECV2_PAUSE) { #ifndef USB_AUDIO_MULTIFUNC enqueue_unique_cmd_with_opp(AUDIO_CMD_RECV_PAUSE, usb_recv_seq, 0, AUDIO_CMD_RECV_CONTINUE); #endif } else if (event == USB_AUDIO_STATE_RECV_CONTINUE || event == USB_AUDIO_STATE_RECV2_CONTINUE) { #ifndef USB_AUDIO_MULTIFUNC enqueue_unique_cmd_with_opp(AUDIO_CMD_RECV_CONTINUE, usb_recv_seq, 0, AUDIO_CMD_RECV_PAUSE); #endif #ifdef USB_AUDIO_DYN_CFG } else if (event == USB_AUDIO_STATE_SET_RECV_RATE) { usb_audio_set_recv_rate(param); } else if (event == USB_AUDIO_STATE_SET_SEND_RATE) { usb_audio_set_send_rate(param); #endif } else { ASSERT(false, "Bad state event"); } } static void usb_audio_acquire_freq(void) { enum HAL_CMU_FREQ_T freq; #if defined(CHIP_BEST1000) && defined(_DUAL_AUX_MIC_) #ifdef SW_CAPTURE_RESAMPLE if (resample_cap_enabled) { freq = HAL_CMU_FREQ_104M; } else #endif if (capture_state == AUDIO_ITF_STATE_STARTED) { #ifdef DUAL_AUX_MIC_MORE_FILTER freq = HAL_CMU_FREQ_104M; #else freq = HAL_CMU_FREQ_78M; #endif } else #else // !(CHIP_BEST1000 && _DUAL_AUX_MIC_) #ifdef SW_CAPTURE_RESAMPLE if (resample_cap_enabled) { #ifdef CHIP_BEST1000 freq = HAL_CMU_FREQ_78M; #else freq = HAL_CMU_FREQ_52M; #endif } else #endif #endif // !(CHIP_BEST1000 && _DUAL_AUX_MIC_) { freq = HAL_CMU_FREQ_52M; } #if defined(USB_HIGH_SPEED) && defined(USB_AUDIO_UAC2) if (playback_state == AUDIO_ITF_STATE_STARTED && sample_rate_play >= AUD_SAMPRATE_352800) { if (freq < HAL_CMU_FREQ_104M) { freq = HAL_CMU_FREQ_104M; } } #endif #ifdef AUDIO_ANC_FB_MC if (freq < HAL_CMU_FREQ_104M) { freq = HAL_CMU_FREQ_104M; } #endif #ifdef __HW_FIR_DSD_PROCESS__ if (freq < HAL_CMU_FREQ_104M) { freq = HAL_CMU_FREQ_104M; } #endif #ifdef USB_AUDIO_SPEECH enum HAL_CMU_FREQ_T speech_freq; speech_freq = speech_process_need_freq(); if (freq < speech_freq) { freq = speech_freq; } #endif hal_sysfreq_req(HAL_SYSFREQ_USER_APP_2, freq); // TRACE(2,"[%s] app_sysfreq_req %d", __FUNCTION__, freq); // TRACE(2,"[%s] sys freq calc : %d\n", __FUNCTION__, // hal_sys_timer_calc_cpu_freq(5, 0)); } static void usb_audio_release_freq(void) { hal_sysfreq_req(HAL_SYSFREQ_USER_APP_2, HAL_CMU_FREQ_32K); } static void usb_audio_update_freq(void) { usb_audio_acquire_freq(); } #ifdef SW_CAPTURE_RESAMPLE static enum AUD_CHANNEL_NUM_T get_capture_resample_chan_num(void) { #if (CHAN_NUM_CAPTURE == CHAN_NUM_SEND) return chan_num_to_enum(CHAN_NUM_CAPTURE); #else return AUD_CHANNEL_NUM_1; #endif } static void capture_stream_resample_config(void) { struct RESAMPLE_CFG_T cfg; enum RESAMPLE_STATUS_T ret; enum AUD_SAMPRATE_T cap_rate; #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) cap_rate = sample_rate_ref_cap; #else cap_rate = sample_rate_cap; #endif #ifndef __AUDIO_RESAMPLE__ if (cap_rate == sample_rate_send) { if (resample_cap_enabled) { TRACE(1, "!!! %s: Disable capture resample", __FUNCTION__); audio_resample_ex_close(resample_id); resample_cap_enabled = false; } } else #endif { if (!resample_cap_enabled) { // Resample chan num is usb send chan num memset(&cfg, 0, sizeof(cfg)); cfg.chans = get_capture_resample_chan_num(); cfg.bits = sample_size_to_enum_capture(sample_size_cap); #ifdef __AUDIO_RESAMPLE__ if (sample_rate_send % AUD_SAMPRATE_8000) { ASSERT(hal_cmu_get_crystal_freq() / (CODEC_FREQ_44_1K_SERIES / sample_rate_send) == cap_rate, "%s: Bad cap_rate=%u with sample_rate_send=%u", __FUNCTION__, cap_rate, sample_rate_send); #if (CODEC_FREQ_26M / CODEC_FREQ_CRYSTAL * CODEC_FREQ_CRYSTAL == CODEC_FREQ_26M) cfg.coef = &resample_coef_50p7k_to_44p1k; #else cfg.coef = &resample_coef_46p8k_to_44p1k; #endif } else { ASSERT(hal_cmu_get_crystal_freq() / (CODEC_FREQ_48K_SERIES / sample_rate_send) == cap_rate, "%s: Bad cap_rate=%u with sample_rate_send=%u", __FUNCTION__, cap_rate, sample_rate_send); #if (CODEC_FREQ_26M / CODEC_FREQ_CRYSTAL * CODEC_FREQ_CRYSTAL == CODEC_FREQ_26M) cfg.coef = &resample_coef_50p7k_to_48k; #else cfg.coef = &resample_coef_46p8k_to_48k; #endif } #else if (sample_rate_send % AUD_SAMPRATE_8000) { ASSERT(CODEC_FREQ_48K_SERIES / (CODEC_FREQ_44_1K_SERIES / sample_rate_send) == cap_rate, "%s: Bad cap_rate=%u with sample_rate_send=%u", __FUNCTION__, cap_rate, sample_rate_send); cfg.coef = &resample_coef_48k_to_44p1k; } else { ASSERT(CODEC_FREQ_44_1K_SERIES / (CODEC_FREQ_48K_SERIES / sample_rate_send) == cap_rate, "%s: Bad cap_rate=%u with sample_rate_send=%u", __FUNCTION__, cap_rate, sample_rate_send); cfg.coef = &resample_coef_44p1k_to_48k; } #endif cfg.buf = resample_history_buf; cfg.size = resample_history_size; TRACE(3, "!!! %s: Enable capture resample %u => %u", __FUNCTION__, cap_rate, sample_rate_send); ret = audio_resample_ex_open(&cfg, &resample_id); ASSERT(ret == RESAMPLE_STATUS_OK, "%s: Failed to init resample: %d", __FUNCTION__, ret); resample_cap_enabled = true; } } } #endif static void usb_audio_init_streams(enum AUDIO_STREAM_REQ_USER_T user) { bool action; action = false; #ifndef DELAY_STREAM_OPEN if (user == AUDIO_STREAM_REQ_USB) { action = true; } #endif #ifdef ANC_L_R_MISALIGN_WORKAROUND if (user == AUDIO_STREAM_REQ_ANC) { action = true; } #endif if (action) { usb_audio_open_codec_stream(AUD_STREAM_PLAYBACK, user); usb_audio_open_codec_stream(AUD_STREAM_CAPTURE, user); } #ifdef ANC_L_R_MISALIGN_WORKAROUND if (user == AUDIO_STREAM_REQ_ANC) { usb_audio_start_codec_stream(AUD_STREAM_PLAYBACK, user); usb_audio_start_codec_stream(AUD_STREAM_CAPTURE, user); } #endif } static void usb_audio_term_streams(enum AUDIO_STREAM_REQ_USER_T user) { // Ensure all the streams for this user are stopped and closed usb_audio_stop_codec_stream(AUD_STREAM_CAPTURE, user); usb_audio_stop_codec_stream(AUD_STREAM_PLAYBACK, user); usb_audio_close_codec_stream(AUD_STREAM_CAPTURE, user); usb_audio_close_codec_stream(AUD_STREAM_PLAYBACK, user); } #if defined(ANDROID_ACCESSORY_SPEC) || defined(CFG_MIC_KEY) static void hid_data_send_handler(enum USB_AUDIO_HID_EVENT_T event, int error) { TRACE(2, "HID SENT: event=0x%04x error=%d", event, error); } #endif static void usb_audio_itf_callback(enum USB_AUDIO_ITF_ID_T id, enum USB_AUDIO_ITF_CMD_T cmd) { if (0) { #ifdef USB_AUDIO_MULTIFUNC } else if (id == USB_AUDIO_ITF_ID_RECV2) { usb_audio_playback2_start(cmd); #endif } else if (id == USB_AUDIO_ITF_ID_RECV) { usb_audio_playback_start(cmd); } else { usb_audio_capture_start(cmd); } } static void usb_audio_mute_callback(enum USB_AUDIO_ITF_ID_T id, uint32_t mute) { if (0) { #ifdef USB_AUDIO_MULTIFUNC } else if (id == USB_AUDIO_ITF_ID_RECV2) { usb_audio_mute2_control(mute); #endif } else if (id == USB_AUDIO_ITF_ID_RECV) { usb_audio_mute_control(mute); } else { usb_audio_cap_mute_control(mute); } } static void usb_audio_set_volume(enum USB_AUDIO_ITF_ID_T id, uint32_t percent) { if (0) { #ifdef USB_AUDIO_MULTIFUNC } else if (id == USB_AUDIO_ITF_ID_RECV2) { usb_audio_vol2_control(percent); #endif } else if (id == USB_AUDIO_ITF_ID_RECV) { usb_audio_vol_control(percent); } else { usb_audio_cap_vol_control(percent); } } static uint32_t usb_audio_get_volume(enum USB_AUDIO_ITF_ID_T id) { uint32_t percent = 0; if (0) { #ifdef USB_AUDIO_MULTIFUNC } else if (id == USB_AUDIO_ITF_ID_RECV2) { percent = usb_audio_get_vol2_percent(); #endif } else if (id == USB_AUDIO_ITF_ID_RECV) { percent = usb_audio_get_vol_percent(); } else { percent = usb_audio_get_cap_vol_percent(); } return percent; } static void usb_audio_xfer_callback(enum USB_AUDIO_ITF_ID_T id, const struct USB_AUDIO_XFER_INFO_T *info) { if (0) { #ifdef USB_AUDIO_MULTIFUNC } else if (id == USB_AUDIO_ITF_ID_RECV2) { usb_audio_data_recv2_handler(info); #endif } else if (id == USB_AUDIO_ITF_ID_RECV) { usb_audio_data_recv_handler(info); } else { usb_audio_data_send_handler(info); } } static void usb_audio_stream_running_handler(void) { enum AUDIO_STREAM_RUNNING_T req; uint32_t lock; req = streams_running_req; if (req == AUDIO_STREAM_RUNNING_NULL) { return; } else if (req == AUDIO_STREAM_RUNNING_ENABLED) { usb_audio_init_streams(AUDIO_STREAM_REQ_ANC); } else if (req == AUDIO_STREAM_RUNNING_DISABLED) { usb_audio_term_streams(AUDIO_STREAM_REQ_ANC); } lock = int_lock(); if (req == streams_running_req) { streams_running_req = AUDIO_STREAM_RUNNING_NULL; } int_unlock(lock); } void usb_audio_keep_streams_running(bool enable) { if (enable) { streams_running_req = AUDIO_STREAM_RUNNING_ENABLED; } else { streams_running_req = AUDIO_STREAM_RUNNING_DISABLED; } // TODO: Move usb_audio_stream_running_handler() into usb_audio_app_loop() ? // How to ensure that streams are opened before ANC is enabled? usb_audio_stream_running_handler(); } #ifdef USB_AUDIO_DYN_CFG static enum AUD_SAMPRATE_T calc_play_sample_rate(enum AUD_SAMPRATE_T usb_rate) { enum AUD_SAMPRATE_T codec_rate; #if defined(CHIP_BEST1000) && defined(ANC_APP) codec_rate = (usb_rate % AUD_SAMPRATE_8000) ? AUD_SAMPRATE_88200 : AUD_SAMPRATE_96000; #else codec_rate = usb_rate; #if defined(__AUDIO_RESAMPLE__) && defined(SW_PLAYBACK_RESAMPLE) if (codec_rate % AUD_SAMPRATE_8000) { codec_rate = hal_cmu_get_crystal_freq() / (CODEC_FREQ_44_1K_SERIES / codec_rate); } else { codec_rate = hal_cmu_get_crystal_freq() / (CODEC_FREQ_48K_SERIES / codec_rate); } #endif #endif return codec_rate; } #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) static enum AUD_SAMPRATE_T calc_anc_cap_sample_rate_best1000(enum AUD_SAMPRATE_T usb_rate, enum AUD_SAMPRATE_T play_rate) { enum AUD_SAMPRATE_T rate_cap; #ifdef ANC_APP #ifdef AUD_PLL_DOUBLE #if defined(_DUAL_AUX_MIC_) || defined(CAPTURE_ANC_DATA) rate_cap = play_rate * 8; #else rate_cap = play_rate * 2; #endif #else // !AUD_PLL_DOUBLE #if defined(_DUAL_AUX_MIC_) || defined(CAPTURE_ANC_DATA) rate_cap = play_rate * 4; #else rate_cap = play_rate; #endif #endif // !AUD_PLL_DOUBLE #else // _DUAL_AUX_MIC_ // Capture reference enum AUD_SAMPRATE_T rate_cap_ref; rate_cap_ref = (usb_rate % AUD_SAMPRATE_8000) ? AUD_SAMPRATE_44100 : AUD_SAMPRATE_48000; rate_cap = rate_cap_ref * 4; #endif return rate_cap; } #endif static enum AUD_SAMPRATE_T calc_cap_sample_rate(enum AUD_SAMPRATE_T usb_rate, enum AUD_SAMPRATE_T play_rate) { #if defined(CHIP_BEST1000) && (defined(ANC_APP) || defined(_DUAL_AUX_MIC_)) return calc_anc_cap_sample_rate_best1000(usb_rate, play_rate); #else // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) enum AUD_SAMPRATE_T codec_rate; #ifdef __AUDIO_RESAMPLE__ codec_rate = usb_rate; #ifdef SW_CAPTURE_RESAMPLE if (codec_rate % AUD_SAMPRATE_8000) { codec_rate = hal_cmu_get_crystal_freq() / (CODEC_FREQ_44_1K_SERIES / codec_rate); } else { codec_rate = hal_cmu_get_crystal_freq() / (CODEC_FREQ_48K_SERIES / codec_rate); } #endif #else // ! __AUDIO_RESAMPLE__ bool usb_rate_44p1k; bool play_rate_44p1k; usb_rate_44p1k = !!(usb_rate % AUD_SAMPRATE_8000); play_rate_44p1k = !!(play_rate % AUD_SAMPRATE_8000); if (usb_rate_44p1k ^ play_rate_44p1k) { // Playback pll is NOT compatible with capture sample rate if (usb_rate_44p1k) { codec_rate = CODEC_FREQ_48K_SERIES / (CODEC_FREQ_44_1K_SERIES / usb_rate); } else { codec_rate = CODEC_FREQ_44_1K_SERIES / (CODEC_FREQ_48K_SERIES / usb_rate); } } else { // Playback pll is compatible with capture sample rate codec_rate = usb_rate; } #endif // !__AUDIO_RESAMPLE__ return codec_rate; #endif // !(CHIP_BEST1000 && (ANC_APP || _DUAL_AUX_MIC_)) } #endif // USB_AUDIO_DYN_CFG static void POSSIBLY_UNUSED usb_audio_update_codec_stream(enum AUD_STREAM_T stream) { bool update_play; bool update_cap; #ifdef STREAM_RATE_BITS_SETUP struct AF_STREAM_CONFIG_T *cfg, stream_cfg; uint32_t ret; #endif update_play = false; update_cap = false; #ifdef USB_AUDIO_DYN_CFG enum AUD_SAMPRATE_T new_recv_rate; enum AUD_SAMPRATE_T new_send_rate; enum AUD_SAMPRATE_T play_rate; enum AUD_SAMPRATE_T cap_rate; uint8_t new_recv_size; uint32_t lock; lock = int_lock(); new_recv_rate = new_sample_rate_recv; new_recv_size = new_sample_size_recv; new_send_rate = new_sample_rate_send; int_unlock(lock); play_rate = sample_rate_play; cap_rate = sample_rate_cap; if (stream == AUD_STREAM_PLAYBACK) { if (sample_rate_recv == new_recv_rate && sample_size_recv == new_recv_size) { // No change goto _done_rate_size_check; } #ifdef AUDIO_PLAYBACK_24BIT if (sample_rate_recv == new_recv_rate && sample_size_recv != new_recv_size) { // No codec change. Only a change in usb sample size TRACE(3, "%s:1: Update recv sample size from %u to %u", __FUNCTION__, sample_size_recv, new_recv_size); sample_size_recv = new_recv_size; update_playback_sync_info(); goto _done_rate_size_check; } #endif } else { if (sample_rate_send == new_send_rate) { // No change goto _done_rate_size_check; } } if (stream == AUD_STREAM_PLAYBACK) { play_rate = calc_play_sample_rate(new_recv_rate); if (sample_rate_play == play_rate) { if (sample_size_recv == new_recv_size) { // No codec change. Only a change in usb sample rate TRACE(3, "%s:1: Update recv sample rate from %u to %u", __FUNCTION__, sample_rate_recv, new_recv_rate); sample_rate_recv = new_recv_rate; update_playback_sync_info(); goto _done_rate_size_check; } } else { #ifndef __AUDIO_RESAMPLE__ bool new_rate_44p1k; bool old_rate_44p1k; new_rate_44p1k = !!(play_rate % AUD_SAMPRATE_8000); old_rate_44p1k = !!(sample_rate_play % AUD_SAMPRATE_8000); if (new_rate_44p1k ^ old_rate_44p1k) { cap_rate = calc_cap_sample_rate(new_send_rate, play_rate); update_cap = true; } #endif } update_play = true; } else { #ifndef __AUDIO_RESAMPLE__ if (playback_state == AUDIO_ITF_STATE_STOPPED) { bool usb_rate_44p1k; bool play_rate_44p1k; usb_rate_44p1k = !!(new_send_rate % AUD_SAMPRATE_8000); play_rate_44p1k = !!(play_rate % AUD_SAMPRATE_8000); if (usb_rate_44p1k ^ play_rate_44p1k) { play_rate = calc_play_sample_rate(usb_rate_44p1k ? AUD_SAMPRATE_44100 : AUD_SAMPRATE_48000); update_play = true; } } #endif cap_rate = calc_cap_sample_rate(new_send_rate, play_rate); if (sample_rate_cap == cap_rate) { // No codec change. Only a change in usb sample rate TRACE(3, "%s:1: Update send sample rate from %u to %u", __FUNCTION__, sample_rate_send, new_send_rate); sample_rate_send = new_send_rate; update_capture_sync_info(); goto _done_rate_size_check; } update_cap = true; } _done_rate_size_check:; #endif #ifdef DSD_SUPPORT bool new_dsd_state; new_dsd_state = usb_dsd_enabled; if (stream == AUD_STREAM_PLAYBACK) { if (codec_dsd_enabled != new_dsd_state) { update_play = true; } } #endif if (!update_play && !update_cap) { return; } // 1) To avoid L/R sample misalignment, streams must be stopped before // changing sample rate 2) To avoid FIFO corruption, streams must be stopped // before changing sample size if (update_cap && codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_STARTED]) { set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_CAP, true); usb_audio_stop_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); } if (update_play && codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_STARTED]) { set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_PLAY, true); usb_audio_stop_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); } if (update_play) { #ifdef USB_AUDIO_DYN_CFG if (sample_rate_recv != new_recv_rate) { TRACE(3, "%s:2: Update recv sample rate from %u to %u", __FUNCTION__, sample_rate_recv, new_recv_rate); sample_rate_recv = new_recv_rate; } if (sample_rate_play != play_rate) { TRACE(3, "%s:2: Update play sample rate from %u to %u", __FUNCTION__, sample_rate_play, play_rate); sample_rate_play = play_rate; } if (sample_size_recv != new_recv_size) { TRACE(3, "%s:2: Update recv sample size from %u to %u", __FUNCTION__, sample_size_recv, new_recv_size); sample_size_recv = new_recv_size; #ifndef AUDIO_PLAYBACK_24BIT uint8_t old_play_size; old_play_size = sample_size_play; sample_size_play = (new_recv_size == 2) ? 2 : 4; TRACE(3, "%s:2: Update play sample size from %u to %u", __FUNCTION__, old_play_size, sample_size_play); #endif } #endif #ifdef DSD_SUPPORT if (codec_dsd_enabled != new_dsd_state) { codec_dsd_enabled = new_dsd_state; #ifdef CODEC_DSD uint8_t old_play_size; old_play_size = sample_size_play; if (codec_dsd_enabled) { playback_size /= ((sample_size_play + 1) / 2); dsd_saved_sample_size = sample_size_play; sample_size_play = 2; } else { playback_size *= ((dsd_saved_sample_size + 1) / 2); sample_size_play = dsd_saved_sample_size; } TRACE(4, "%s:2: CODEC_DSD=%u update play sample size from %u to %u", __FUNCTION__, codec_dsd_enabled, old_play_size, sample_size_play); #endif } #endif } if (update_cap) { #ifdef USB_AUDIO_DYN_CFG if (sample_rate_send != new_send_rate) { TRACE(3, "%s:2: Update send sample rate from %u to %u", __FUNCTION__, sample_rate_send, new_send_rate); sample_rate_send = new_send_rate; } if (sample_rate_cap != cap_rate) { TRACE(3, "%s:2: Update cap sample rate from %u to %u", __FUNCTION__, sample_rate_cap, cap_rate); sample_rate_cap = cap_rate; } #endif } #if defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY) playback_size = calc_playback_size(sample_rate_play); capture_size = calc_capture_size(sample_rate_cap); #endif #ifdef SW_CAPTURE_RESAMPLE // Check whether to start capture resample if (update_cap && capture_state == AUDIO_ITF_STATE_STARTED) { capture_stream_resample_config(); } #endif #ifdef STREAM_RATE_BITS_SETUP if (update_play) { update_playback_sync_info(); ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &cfg, true); if (ret == 0) { // Changes in AF_STREAM_CONFIG_T::bits must be in another cfg variable stream_cfg = *cfg; #ifdef CODEC_DSD if (codec_dsd_enabled) { stream_cfg.bits = AUD_BITS_24; } else #endif { stream_cfg.bits = sample_size_to_enum_playback(sample_size_play); } stream_cfg.sample_rate = sample_rate_play; #if (defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY)) || \ defined(CODEC_DSD) stream_cfg.data_size = playback_size; #endif af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_PLAYBACK, &stream_cfg); } #ifdef AUDIO_ANC_FB_MC ret = af_stream_get_cfg(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, &cfg, true); if (ret == 0) { // Changes in AF_STREAM_CONFIG_T::bits must be in another cfg variable stream_cfg = *cfg; stream_cfg.bits = sample_size_to_enum_playback(sample_size_play); if (sample_rate_play == AUD_SAMPRATE_8000) { playback_samplerate_ratio = 8 * 6; } else if (sample_rate_play == AUD_SAMPRATE_16000) { playback_samplerate_ratio = 8 * 3; } else if ((sample_rate_play == AUD_SAMPRATE_44100) || (sample_rate_play == AUD_SAMPRATE_48000) || (sample_rate_play == AUD_SAMPRATE_50781)) { playback_samplerate_ratio = 8; } else if ((sample_rate_play == AUD_SAMPRATE_88200) || (sample_rate_play == AUD_SAMPRATE_96000)) { playback_samplerate_ratio = 4; } else if ((sample_rate_play == AUD_SAMPRATE_176400) || (sample_rate_play == AUD_SAMPRATE_192000)) { playback_samplerate_ratio = 2; } else if (sample_rate_play == AUD_SAMPRATE_384000) { playback_samplerate_ratio = 1; } else { playback_samplerate_ratio = 1; ASSERT(false, "Music cancel can't support playback sample rate:%d", sample_rate_play); } stream_cfg.data_ptr = playback_buf + playback_size; stream_cfg.data_size = playback_size * playback_samplerate_ratio; stream_cfg.sample_rate = sample_rate_play; af_stream_setup(AUD_STREAM_ID_2, AUD_STREAM_PLAYBACK, &stream_cfg); anc_mc_run_setup((sample_rate_play * playback_samplerate_ratio) / 8); } #endif } if (update_cap) { update_capture_sync_info(); ret = af_stream_get_cfg(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &cfg, true); if (ret == 0) { stream_cfg = *cfg; stream_cfg.bits = sample_size_to_enum_capture(sample_size_cap); #if defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY) stream_cfg.data_size = capture_size; #endif stream_cfg.sample_rate = sample_rate_cap; af_stream_setup(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, &stream_cfg); } } #else // !STREAM_RATE_BITS_SETUP // Close streams if (update_cap && codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_OPENED]) { usb_audio_close_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); } if (update_play && codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_OPENED]) { usb_audio_close_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); } // Open streams if (update_play && codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_OPENED]) { usb_audio_open_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); } if (update_cap && codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_OPENED]) { usb_audio_open_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); } #endif // !STREAM_RATE_BITS_SETUP if (update_play && codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_STARTED]) { usb_audio_start_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_PLAY, false); } if (update_cap && codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_STARTED]) { usb_audio_start_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_CAP, false); } } static void start_play(uint8_t seq) { if (playback_state == AUDIO_ITF_STATE_STOPPED) { #ifdef FREQ_RESP_EQ freq_resp_eq_init(); #endif #ifdef DELAY_STREAM_OPEN usb_audio_open_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USB); #endif #ifdef NOISE_GATING last_high_signal_time = hal_sys_timer_get(); #ifdef NOISE_REDUCTION last_nr_restore_time = hal_sys_timer_get(); #endif #endif usb_audio_start_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USB); playback_state = AUDIO_ITF_STATE_STARTED; } codec_play_seq = seq; playback_paused = 0; usb_audio_update_freq(); } static void usb_audio_cmd_start_play(uint8_t seq) { #if defined(USB_AUDIO_DYN_CFG) && defined(USB_AUDIO_UAC2) usb_audio_update_codec_stream(AUD_STREAM_PLAYBACK); #endif start_play(seq); } static void usb_audio_cmd_stop_play(void) { if (playback_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USB); #ifdef PA_ON_OFF_KEY if (pa_on_off_muted) { pa_on_off_muted = false; if (mute_user_map == 0) { usb_audio_codec_unmute(CODEC_MUTE_USER_ALL); } } #endif #ifdef NOISE_GATING // Restore the noise gating status if (mute_user_map & (1 << CODEC_MUTE_USER_NOISE_GATING)) { usb_audio_codec_unmute(CODEC_MUTE_USER_NOISE_GATING); } #ifdef NOISE_REDUCTION restore_noise_reduction_status(); #endif #endif #ifdef DELAY_STREAM_OPEN usb_audio_close_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USB); #endif playback_paused = 0; playback_state = AUDIO_ITF_STATE_STOPPED; #ifdef DSD_SUPPORT if (codec_dsd_enabled) { usb_audio_update_codec_stream(AUD_STREAM_PLAYBACK); } #endif } usb_audio_update_freq(); } static void start_capture(uint8_t seq) { if (capture_state == AUDIO_ITF_STATE_STOPPED) { #ifdef SW_CAPTURE_RESAMPLE // Check whether to start capture resample capture_stream_resample_config(); #endif #ifdef DELAY_STREAM_OPEN usb_audio_open_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USB); #endif usb_audio_start_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USB); capture_state = AUDIO_ITF_STATE_STARTED; } codec_cap_seq = seq; usb_audio_update_freq(); } static void usb_audio_cmd_start_capture(uint8_t seq) { start_capture(seq); } static void usb_audio_cmd_stop_capture(void) { if (capture_state == AUDIO_ITF_STATE_STARTED) { usb_audio_stop_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USB); #ifdef DELAY_STREAM_OPEN usb_audio_close_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USB); #endif #ifdef SW_CAPTURE_RESAMPLE if (resample_cap_enabled) { audio_resample_ex_close(resample_id); resample_cap_enabled = false; } #endif capture_state = AUDIO_ITF_STATE_STOPPED; } usb_audio_update_freq(); } static void usb_audio_cmd_set_volume(void) { #ifndef USB_AUDIO_MULTIFUNC playback_vol = new_playback_vol; #endif usb_audio_set_codec_volume(AUD_STREAM_PLAYBACK, playback_vol); #ifdef UNMUTE_WHEN_SET_VOL // Unmute if muted before if (mute_user_map & (1 << CODEC_MUTE_USER_CMD)) { usb_audio_codec_unmute(CODEC_MUTE_USER_CMD); } #endif } static void usb_audio_cmd_set_cap_volume(void) { capture_vol = new_capture_vol; usb_audio_set_codec_volume(AUD_STREAM_CAPTURE, capture_vol); } static void usb_audio_cmd_mute_ctrl(void) { uint8_t mute; #ifdef USB_AUDIO_MULTIFUNC mute = new_mute_state && new_mute2_state; #else mute = new_mute_state; #endif if (mute) { usb_audio_codec_mute(CODEC_MUTE_USER_CMD); } else { usb_audio_codec_unmute(CODEC_MUTE_USER_CMD); } } static void usb_audio_cmd_cap_mute_ctrl(void) { uint8_t mute; mute = new_cap_mute_state; af_stream_mute(AUD_STREAM_ID_0, AUD_STREAM_CAPTURE, mute); } static void usb_audio_cmd_usb_state(enum AUDIO_CMD_T cmd) { usb_audio_cmd_stop_capture(); usb_audio_cmd_stop_play(); if (cmd == AUDIO_CMD_USB_RESET || cmd == AUDIO_CMD_USB_WAKEUP) { usb_audio_acquire_freq(); if (cmd == AUDIO_CMD_USB_RESET) { usb_audio_term_streams(AUDIO_STREAM_REQ_USB); } usb_audio_reset_codec_stream_state(cmd == AUDIO_CMD_USB_RESET); usb_audio_init_streams(AUDIO_STREAM_REQ_USB); } else if (cmd == AUDIO_CMD_USB_DISCONNECT || cmd == AUDIO_CMD_USB_SLEEP) { usb_audio_term_streams(AUDIO_STREAM_REQ_USB); usb_audio_reset_codec_stream_state(cmd == AUDIO_CMD_USB_DISCONNECT); if (cmd == AUDIO_CMD_USB_DISCONNECT || usb_configured) { usb_audio_release_freq(); } } else if (cmd == AUDIO_CMD_USB_CONFIG) { usb_configured = 1; usb_audio_reset_codec_stream_state(true); } } static void usb_audio_cmd_recv_pause(uint8_t seq) { TRACE(3, "%s: Recv pause: seq=%u usb_recv_seq=%u", __FUNCTION__, seq, usb_recv_seq); if (seq == usb_recv_seq) { usb_audio_cmd_stop_play(); playback_paused = 1; } } static void usb_audio_cmd_recv_continue(uint8_t seq) { TRACE(3, "%s: Recv continue: seq=%u usb_recv_seq=%u", __FUNCTION__, seq, usb_recv_seq); if (seq == usb_recv_seq && playback_paused) { start_play(seq); // playback_paused = 0; } } #ifdef USB_AUDIO_DYN_CFG static void usb_audio_cmd_set_playback_rate(uint8_t seq, uint8_t index) { #ifndef USB_AUDIO_UAC2 if (seq != usb_recv_seq) { TRACE(3, "%s: Bad seq: seq=%u usb_recv_seq=%u", __FUNCTION__, seq, usb_recv_seq); return; } #endif usb_audio_update_codec_stream(AUD_STREAM_PLAYBACK); #ifndef USB_AUDIO_UAC2 start_play(seq); #endif } static void usb_audio_cmd_set_capture_rate(uint8_t seq, uint8_t index) { #ifndef USB_AUDIO_UAC2 if (seq != usb_send_seq) { TRACE(3, "%s: Bad seq: seq=%u usb_send_seq=%u", __FUNCTION__, seq, usb_send_seq); return; } #endif usb_audio_update_codec_stream(AUD_STREAM_CAPTURE); #ifndef USB_AUDIO_UAC2 start_capture(seq); #endif } #endif static void usb_audio_cmd_reset_codec(void) { TRACE(1, "%s: RESET CODEC", __FUNCTION__); // Regarding PLL reconfiguration, stream stop and start are enough. // Complete DAC/ADC reset (including analog parts) can be achieved by // stream close and open, which need to invoke explicitly here if // DELAY_STREAM_OPEN is not defined. if (codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_STARTED]) { set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_CAP, true); usb_audio_stop_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); } if (codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_STARTED]) { set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_PLAY, true); usb_audio_stop_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); } rate_tune_ratio[AUD_STREAM_PLAYBACK] = 0; rate_tune_ratio[AUD_STREAM_CAPTURE] = 0; #ifdef __AUDIO_RESAMPLE__ #ifdef PLL_TUNE_SAMPLE_RATE af_codec_tune_resample_rate(AUD_STREAM_PLAYBACK, rate_tune_ratio[AUD_STREAM_PLAYBACK]); af_codec_tune_resample_rate(AUD_STREAM_CAPTURE, rate_tune_ratio[AUD_STREAM_CAPTURE]); #elif defined(PLL_TUNE_XTAL) af_codec_tune_xtal(rate_tune_ratio[AUD_STREAM_PLAYBACK]); #endif #else af_codec_tune_pll(rate_tune_ratio[AUD_STREAM_PLAYBACK]); #endif if (codec_stream_map[AUD_STREAM_PLAYBACK][AUDIO_STREAM_STARTED]) { usb_audio_start_codec_stream(AUD_STREAM_PLAYBACK, AUDIO_STREAM_REQ_USER_ALL); set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_PLAY, false); } if (codec_stream_map[AUD_STREAM_CAPTURE][AUDIO_STREAM_STARTED]) { usb_audio_start_codec_stream(AUD_STREAM_CAPTURE, AUDIO_STREAM_REQ_USER_ALL); set_codec_config_status(CODEC_CONFIG_LOCK_RESTART_CAP, false); } } #ifdef NOISE_GATING static void usb_audio_cmd_noise_gating(void) { uint32_t lock; enum NOISE_GATING_CMD_T cmd; lock = int_lock(); cmd = noise_gating_cmd; noise_gating_cmd = NOISE_GATING_CMD_NULL; int_unlock(lock); TRACE(3, "%s: cmd=%d map=0x%02X", __FUNCTION__, cmd, mute_user_map); if (cmd == NOISE_GATING_CMD_MUTE) { if ((mute_user_map & (1 << CODEC_MUTE_USER_NOISE_GATING)) == 0) { usb_audio_codec_mute(CODEC_MUTE_USER_NOISE_GATING); } } else if (cmd == NOISE_GATING_CMD_UNMUTE) { if (mute_user_map & (1 << CODEC_MUTE_USER_NOISE_GATING)) { usb_audio_codec_unmute(CODEC_MUTE_USER_NOISE_GATING); } } } #ifdef NOISE_REDUCTION static void restore_noise_reduction_status(void) { if (nr_active) { nr_active = false; af_codec_set_noise_reduction(false); } prev_samp_positive[0] = prev_samp_positive[1] = false; memset(prev_zero_diff, 0, sizeof(prev_zero_diff)); memset(cur_zero_diff, 0, sizeof(cur_zero_diff)); nr_cont_cnt = 0; } static void usb_audio_cmd_noise_reduction(void) { uint32_t lock; enum NOISE_REDUCTION_CMD_T cmd; lock = int_lock(); cmd = noise_reduction_cmd; noise_reduction_cmd = NOISE_REDUCTION_CMD_NULL; int_unlock(lock); TRACE(2, "%s: cmd=%d", __FUNCTION__, cmd); if (cmd == NOISE_REDUCTION_CMD_FIRE) { nr_active = true; af_codec_set_noise_reduction(true); } else if (cmd == NOISE_REDUCTION_CMD_RESTORE) { nr_active = false; af_codec_set_noise_reduction(false); } } #endif #endif static void usb_audio_cmd_tune_rate(enum AUD_STREAM_T stream) { #ifdef __AUDIO_RESAMPLE__ #ifdef PLL_TUNE_SAMPLE_RATE bool update_play, update_cap; update_play = true; update_cap = false; #ifdef UAUD_SYNC_STREAM_TARGET if (stream == AUD_STREAM_PLAYBACK) { update_play = true; update_cap = false; } else { update_play = false; update_cap = true; } #else update_play = true; update_cap = true; #endif #ifdef SW_RESAMPLE if (update_play) { audio_resample_ex_set_ratio_step(play_resample_id, nominal_ratio_step * rate_tune_ratio[AUD_STREAM_PLAYBACK]); } if (update_cap) { audio_resample_ex_set_ratio_step(cap_resample_id, nominal_ratio_step * rate_tune_ratio[AUD_STREAM_CAPTURE]); } #else if (update_play) { af_codec_tune_resample_rate(AUD_STREAM_PLAYBACK, rate_tune_ratio[AUD_STREAM_PLAYBACK]); } if (update_cap) { af_codec_tune_resample_rate(AUD_STREAM_CAPTURE, rate_tune_ratio[AUD_STREAM_CAPTURE]); } #endif #elif defined(PLL_TUNE_XTAL) af_codec_tune_xtal(rate_tune_ratio[AUD_STREAM_PLAYBACK]); #endif #else // !__AUDIO_RESAMPLE__ af_codec_tune_pll(rate_tune_ratio[AUD_STREAM_PLAYBACK]); #endif // !__AUDIO_RESAMPLE__ } #ifdef DSD_SUPPORT static void usb_audio_cmd_set_dsd_cfg(void) { if (codec_dsd_enabled != usb_dsd_enabled) { TRACE(3, "%s: %d => %d", __FUNCTION__, codec_dsd_enabled, usb_dsd_enabled); usb_audio_update_codec_stream(AUD_STREAM_PLAYBACK); } } #endif #ifdef PERF_TEST_POWER_KEY static void test_cmd_perf_test_power(void) { perft_power_type++; if (perft_power_type >= HAL_CODEC_PERF_TEST_QTY) { perft_power_type = 0; } TRACE(2, "%s: %d", __FUNCTION__, perft_power_type); af_codec_set_perf_test_power(perft_power_type); } #endif #ifdef PA_ON_OFF_KEY static void test_cmd_pa_on_off(void) { pa_on_off_muted = !pa_on_off_muted; TRACE(2, "%s: %d", __FUNCTION__, pa_on_off_muted); if (pa_on_off_muted) { usb_audio_codec_mute(CODEC_MUTE_USER_ALL); } else { usb_audio_codec_unmute(CODEC_MUTE_USER_ALL); #ifdef PERF_TEST_POWER_KEY af_codec_set_perf_test_power(perft_power_type); #endif } } #endif static void usb_audio_cmd_handler(void *param) { uint32_t data; enum AUDIO_CMD_T cmd; uint8_t seq; uint8_t POSSIBLY_UNUSED arg; hal_cpu_wake_unlock(USB_AUDIO_CPU_WAKE_USER); while (safe_queue_get(&cmd_queue, &data) == 0) { cmd = EXTRACT_CMD(data); seq = EXTRACT_SEQ(data); arg = EXTRACT_ARG(data); TRACE(4, "%s: cmd=%d seq=%d arg=%d", __FUNCTION__, cmd, seq, arg); switch (cmd) { case AUDIO_CMD_START_PLAY: usb_audio_cmd_start_play(seq); break; case AUDIO_CMD_STOP_PLAY: usb_audio_cmd_stop_play(); break; case AUDIO_CMD_START_CAPTURE: usb_audio_cmd_start_capture(seq); break; case AUDIO_CMD_STOP_CAPTURE: usb_audio_cmd_stop_capture(); break; case AUDIO_CMD_SET_VOLUME: usb_audio_cmd_set_volume(); break; case AUDIO_CMD_SET_CAP_VOLUME: usb_audio_cmd_set_cap_volume(); break; case AUDIO_CMD_MUTE_CTRL: usb_audio_cmd_mute_ctrl(); break; case AUDIO_CMD_CAP_MUTE_CTRL: usb_audio_cmd_cap_mute_ctrl(); break; case AUDIO_CMD_USB_RESET: case AUDIO_CMD_USB_DISCONNECT: case AUDIO_CMD_USB_CONFIG: case AUDIO_CMD_USB_SLEEP: case AUDIO_CMD_USB_WAKEUP: usb_audio_cmd_usb_state(cmd); break; case AUDIO_CMD_RECV_PAUSE: usb_audio_cmd_recv_pause(seq); break; case AUDIO_CMD_RECV_CONTINUE: usb_audio_cmd_recv_continue(seq); break; #ifdef USB_AUDIO_DYN_CFG case AUDIO_CMD_SET_RECV_RATE: usb_audio_cmd_set_playback_rate(seq, arg); break; case AUDIO_CMD_SET_SEND_RATE: usb_audio_cmd_set_capture_rate(seq, arg); break; #endif case AUDIO_CMD_RESET_CODEC: usb_audio_cmd_reset_codec(); break; #ifdef NOISE_GATING case AUDIO_CMD_NOISE_GATING: usb_audio_cmd_noise_gating(); break; #ifdef NOISE_REDUCTION case AUDIO_CMD_NOISE_REDUCTION: usb_audio_cmd_noise_reduction(); break; #endif #endif case AUDIO_CMD_TUNE_RATE: usb_audio_cmd_tune_rate((enum AUD_STREAM_T)arg); break; #ifdef DSD_SUPPORT case AUDIO_CMD_SET_DSD_CFG: usb_audio_cmd_set_dsd_cfg(); break; #endif #ifdef PERF_TEST_POWER_KEY case TEST_CMD_PERF_TEST_POWER: test_cmd_perf_test_power(); break; #endif #ifdef PA_ON_OFF_KEY case TEST_CMD_PA_ON_OFF: test_cmd_pa_on_off(); break; #endif default: ASSERT(false, "%s: Invalid cmd %d", __FUNCTION__, cmd); break; } } } void usb_audio_app_init(const struct USB_AUDIO_BUF_CFG *cfg) { #ifdef USB_AUDIO_DYN_CFG ASSERT(cfg->play_size / MAX_FRAME_SIZE_PLAYBACK < cfg->recv_size / MAX_FRAME_SIZE_RECV, "%s: play frames %u should < recv frames %u", __FUNCTION__, cfg->play_size / MAX_FRAME_SIZE_PLAYBACK, cfg->recv_size / MAX_FRAME_SIZE_RECV); ASSERT(cfg->cap_size / MAX_FRAME_SIZE_CAPTURE < cfg->send_size / MAX_FRAME_SIZE_SEND, "%s: cap frames %u should < send frames %u", __FUNCTION__, cfg->cap_size / MAX_FRAME_SIZE_CAPTURE, cfg->send_size / MAX_FRAME_SIZE_SEND); #else ASSERT( cfg->play_size / FRAME_SIZE_PLAYBACK < cfg->recv_size / FRAME_SIZE_RECV, "%s: play frames %u should < recv frames %u", __FUNCTION__, cfg->play_size / FRAME_SIZE_PLAYBACK, cfg->recv_size / FRAME_SIZE_RECV); ASSERT(cfg->cap_size / FRAME_SIZE_CAPTURE < cfg->send_size / FRAME_SIZE_SEND, "%s: cap frames %u should < send frames %u", __FUNCTION__, cfg->cap_size / FRAME_SIZE_CAPTURE, cfg->send_size / FRAME_SIZE_SEND); #endif #ifdef SW_CAPTURE_RESAMPLE enum AUD_CHANNEL_NUM_T chans; enum AUD_BITS_T bits; uint8_t phase_coef_num; uint32_t resamp_calc_size; chans = get_capture_resample_chan_num(); bits = sample_size_to_enum_capture(sample_size_cap); // Max phase coef num phase_coef_num = 100; resamp_calc_size = audio_resample_ex_get_buffer_size(chans, bits, phase_coef_num); ASSERT(cfg->resample_size > resamp_calc_size, "%s: Resample size too small %u (should > %u)", __FUNCTION__, cfg->resample_size, resamp_calc_size); resample_history_buf = (uint8_t *)ALIGN((uint32_t)cfg->resample_buf, 4); resample_history_size = resamp_calc_size; resample_input_buf = (uint8_t *)resample_history_buf + resample_history_size; ASSERT(cfg->resample_buf + cfg->resample_size > resample_input_buf, "%s: Resample size too small: %u", __FUNCTION__, cfg->resample_size); resample_input_size = cfg->resample_buf + cfg->resample_size - resample_input_buf; #endif playback_buf = cfg->play_buf; capture_buf = cfg->cap_buf; usb_recv_buf = cfg->recv_buf; usb_send_buf = cfg->send_buf; playback_eq_buf = cfg->eq_buf; playback_eq_size = cfg->eq_size; #if defined(USB_AUDIO_DYN_CFG) && defined(KEEP_SAME_LATENCY) playback_max_size = cfg->play_size; capture_max_size = cfg->cap_size; usb_recv_max_size = cfg->recv_size; usb_send_max_size = cfg->send_size; #else playback_size = cfg->play_size; capture_size = cfg->cap_size; usb_recv_size = cfg->recv_size; usb_send_size = cfg->send_size; #endif playback_pos = 0; usb_recv_rpos = 0; usb_recv_wpos = cfg->recv_size / 2; capture_pos = 0; usb_send_rpos = cfg->send_size / 2; usb_send_wpos = 0; #ifdef USB_AUDIO_MULTIFUNC usb_recv2_buf = cfg->recv2_buf; usb_recv2_size = cfg->recv2_size; usb_recv2_rpos = 0; usb_recv2_wpos = cfg->recv2_size / 2; #endif playback_info.id = 0; playback_info.sync_thresh = DIFF_SYNC_THRESH_PLAYBACK; playback_info.diff_avg_cnt = DIFF_AVG_CNT; #ifdef TARGET_TO_MAX_DIFF playback_info.diff_target_enabled = true; playback_info.max_target_ratio = MAX_TARGET_RATIO; playback_info.time_to_ms = NULL; #endif capture_info.id = 1; capture_info.sync_thresh = DIFF_SYNC_THRESH_CAPTURE; capture_info.diff_avg_cnt = DIFF_AVG_CNT; #ifdef TARGET_TO_MAX_DIFF capture_info.diff_target_enabled = true; capture_info.max_target_ratio = MAX_TARGET_RATIO; capture_info.time_to_ms = NULL; #endif safe_queue_init(&cmd_queue, cmd_list, CMD_LIST_SIZE); #ifdef USB_AUDIO_PWRKEY_TEST hal_cmu_simu_set_val(0); #endif } void usb_audio_app_term(void) { playback_buf = NULL; playback_size = 0; capture_buf = NULL; capture_size = 0; usb_recv_buf = NULL; usb_recv_size = 0; usb_send_buf = NULL; usb_send_size = 0; playback_pos = 0; usb_recv_rpos = 0; usb_recv_wpos = 0; capture_pos = 0; usb_send_rpos = 0; usb_send_wpos = 0; #ifdef USB_AUDIO_MULTIFUNC usb_recv2_buf = NULL; usb_recv2_size = 0; usb_recv2_rpos = 0; usb_recv2_wpos = 0; #endif } void usb_audio_app(bool on) { static const struct USB_AUDIO_CFG_T usb_audio_cfg = { .recv_sample_rate = SAMPLE_RATE_RECV, .send_sample_rate = SAMPLE_RATE_SEND, .itf_callback = usb_audio_itf_callback, .mute_callback = usb_audio_mute_callback, .set_volume = usb_audio_set_volume, .get_volume = usb_audio_get_volume, .state_callback = usb_audio_state_control, .xfer_callback = usb_audio_xfer_callback, #if defined(ANDROID_ACCESSORY_SPEC) || defined(CFG_MIC_KEY) // Applications are responsible for clearing HID events .hid_send_callback = hid_data_send_handler, #else // HID events will be cleared automatically once they are sent .hid_send_callback = NULL, #endif #ifdef _VENDOR_MSG_SUPPT_ .vendor_msg_callback = usb_vendor_callback, .vendor_rx_buf = vendor_msg_rx_buf, .vendor_rx_size = VENDOR_RX_BUF_SZ, #endif }; static bool isRun = false; int ret; if (isRun == on) return; else isRun = on; TRACE(2, "%s: on=%d", __FUNCTION__, on); if (on) { usb_audio_acquire_freq(); usb_audio_reset_usb_stream_state(true); usb_audio_reset_codec_stream_state(true); #ifdef USB_AUDIO_DYN_CFG sample_rate_recv = new_sample_rate_recv = usb_audio_cfg.recv_sample_rate; sample_rate_send = new_sample_rate_send = usb_audio_cfg.send_sample_rate; // Init codec sample rates after initializing usb sample rates sample_rate_play = calc_play_sample_rate(sample_rate_recv); sample_rate_cap = calc_cap_sample_rate(sample_rate_send, sample_rate_play); // TODO: Check whether 16-bit sample is enabled sample_size_recv = new_sample_size_recv = 2; #ifndef AUDIO_PLAYBACK_24BIT sample_size_play = 2; #endif #ifdef KEEP_SAME_LATENCY usb_recv_size = calc_usb_recv_size(sample_rate_recv, sample_size_recv); usb_send_size = calc_usb_send_size(sample_rate_send); playback_size = calc_playback_size(sample_rate_play); capture_size = calc_capture_size(sample_rate_cap); #endif #endif TRACE(3, "CODEC playback sample: rate=%u size=%u chan=%u", sample_rate_play, sample_size_play, CHAN_NUM_PLAYBACK); TRACE(3, "CODEC capture sample: rate=%u size=%u chan=%u", sample_rate_cap, sample_size_cap, CHAN_NUM_CAPTURE); TRACE(2, "USB recv sample: rate=%u size=%u", sample_rate_recv, sample_size_recv); TRACE(2, "USB send sample: rate=%u size=%u", sample_rate_send, sample_size_send); usb_audio_init_streams(AUDIO_STREAM_REQ_USB); pmu_usb_config(PMU_USB_CONFIG_TYPE_DEVICE); ret = usb_audio_open(&usb_audio_cfg); ASSERT(ret == 0, "usb_audio_open failed: %d", ret); } else { usb_audio_close(); pmu_usb_config(PMU_USB_CONFIG_TYPE_NONE); usb_audio_term_streams(AUDIO_STREAM_REQ_USB); usb_audio_reset_usb_stream_state(true); usb_audio_reset_codec_stream_state(true); usb_audio_release_freq(); } } static void app_key_trace(uint32_t line, enum HAL_KEY_CODE_T code, enum HAL_KEY_EVENT_T event, enum USB_AUDIO_HID_EVENT_T uevt, int state) { #ifdef KEY_TRACE TRACE(5, "APPKEY/%u: code=%d event=%d uevt=%s state=%d", line, code, event, usb_audio_get_hid_event_name(uevt), state); #endif } int usb_audio_app_key(enum HAL_KEY_CODE_T code, enum HAL_KEY_EVENT_T event) { int i; enum USB_AUDIO_HID_EVENT_T uevt; int state; if (event == HAL_KEY_EVENT_CLICK && playback_state == AUDIO_ITF_STATE_STARTED) { #ifdef PERF_TEST_POWER_KEY if (code == PERF_TEST_POWER_KEY) { enqueue_unique_cmd(TEST_CMD_PERF_TEST_POWER); } #endif #ifdef PA_ON_OFF_KEY if (code == PA_ON_OFF_KEY) { enqueue_unique_cmd(TEST_CMD_PA_ON_OFF); } #endif } #ifdef USB_AUDIO_PWRKEY_TEST if (code == HAL_KEY_CODE_PWR) { uevt = hal_cmu_simu_get_val(); if (uevt == 0) { uevt = USB_AUDIO_HID_VOL_UP; } #if defined(ANDROID_ACCESSORY_SPEC) || defined(CFG_MIC_KEY) if (event == HAL_KEY_EVENT_DOWN || event == HAL_KEY_EVENT_UP) { state = (event != HAL_KEY_EVENT_UP); app_key_trace(__LINE__, code, event, uevt, state); usb_audio_hid_set_event(uevt, state); } // The key event has been processed return 0; #else if (event == HAL_KEY_EVENT_CLICK) { state = 1; app_key_trace(__LINE__, code, event, uevt, state); usb_audio_hid_set_event(uevt, state); return 0; } // Let other applications check the key event return 1; #endif } #endif if (code != HAL_KEY_CODE_NONE) { for (i = 0; i < ARRAY_SIZE(key_map); i++) { if (key_map[i].key_code == code && (key_map[i].key_event_bitset & (1 << event))) { break; } } if (i < ARRAY_SIZE(key_map)) { uevt = key_map[i].hid_event; if (uevt != 0) { #if defined(ANDROID_ACCESSORY_SPEC) || defined(CFG_MIC_KEY) state = (event != HAL_KEY_EVENT_UP); #else state = 1; #endif app_key_trace(__LINE__, code, event, uevt, state); usb_audio_hid_set_event(uevt, state); // The key event has been processed return 0; } } } // Let other applications check the key event return 1; } #ifdef ANC_APP extern bool anc_usb_app_get_status(); static uint8_t anc_status = 0; static uint8_t anc_status_record = 0xff; #endif void usb_audio_eq_loop(void) { #ifdef ANC_APP anc_status = anc_usb_app_get_status(); if (anc_status_record != anc_status && eq_opened == 1) { anc_status_record = anc_status; TRACE(2, "[%s]anc_status = %d", __func__, anc_status); #ifdef __SW_IIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_SW_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_SW_IIR, anc_status)); #endif #ifdef __HW_FIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_HW_FIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_FIR, anc_status)); #endif #ifdef __HW_DAC_IIR_EQ_PROCESS__ usb_audio_set_eq( AUDIO_EQ_TYPE_HW_DAC_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_DAC_IIR, anc_status)); #endif #ifdef __HW_IIR_EQ_PROCESS__ usb_audio_set_eq(AUDIO_EQ_TYPE_HW_IIR, usb_audio_get_eq_index(AUDIO_EQ_TYPE_HW_IIR, anc_status)); #endif } #endif } void usb_audio_app_loop(void) { usb_audio_cmd_handler(NULL); usb_audio_eq_loop(); #ifndef RTOS extern void af_thread(void const *argument); af_thread(NULL); #endif } uint32_t usb_audio_get_capture_sample_rate(void) { return sample_rate_cap; }