ANC自适应通透ANCAdaptive leakthrough
1. 关闭热敏检测功能:
2. 用MDE打开ADK_r784软件,打开ANC和自适应ANC的宏定义;
添加下列宏定义:ENABLE_ANC;
ENABLE_ENHANCED_ ANC;
ENABLE_ADAPTIVE_ANC;
ENABLE_ANC_AAH;
ENABLE_ANC_AAH_CC;
3. 在fw_cfg->subsys3_comfig2.htf文件中设置FF和FB Mic,本次案例FB是模拟MIC,在MIC1位置, instance0 channel A中;FF是数字MIC,放在instance2 channel A中;FF数字MIC的对应实际的PIO为PIO16/PIO17;
/*!
\copyright Copyright (c) 2020-2023 Qualcomm Technologies International, Ltd.
All Rights Reserved.
Qualcomm Technologies International, Ltd. Confidential and Proprietary.
\version
\file kymera_adaptive_anc.c
\brief Kymera Adaptive ANC code
*/
#include "kymera_adaptive_anc.h"
#include "kymera_dsp_clock.h"
#include "kymera_internal_msg_ids.h"
#include "kymera_lock.h"
#include "kymera_config.h"
#include "kymera_state.h"
#include "kymera_tones_prompts.h"
#include "anc_state_manager.h"
#include "microphones.h"
#include "kymera_aec.h"
#include "kymera_va.h"
#include "kymera_mic_if.h"
#include "kymera_output_if.h"
#include "kymera_data.h"
#include "kymera_setup.h"
#include <vmal.h>
#include <file.h>
#include <stdlib.h>
#include <cap_id_prim.h>
#include <opmsg_prim.h>
#include "kymera_fit_test.h"
#include "kymera_anc_common.h"
#ifdef ENABLE_ADAPTIVE_ANC
#define MAX_CHAIN (3)
#define CHAIN_MIC_REF_PATH_SPLITTER (MAX_CHAIN-1)
#define CHAIN_FBC (CHAIN_MIC_REF_PATH_SPLITTER-1)
#define CHAIN_AANC (CHAIN_FBC-1)
#define AANC_USB_AUDIO_MIC_CHANNELS 2 /* Number of mic and speaker channels in the audio data stream */
#define AANC_USB_AUDIO_SPKR_CHANNELS 1 /* Number of mic and speaker channels in the audio data stream */
#define AANC_SAMPLE_RATE 16000 /* Only 16KHz supported for anc tuning */
#define MAX_AANC_MICS (2)
#define kymeraAdaptiveAnc_IsAancActive() (kymeraAdaptiveAnc_GetChain(CHAIN_AANC) != NULL)
#define kymeraAdaptiveAnc_PanicIfNotActive() if(!kymeraAdaptiveAnc_IsAancActive()) \
Panic()
#define kymeraAdaptiveAnc_IsSplitterInMicRefPathCreated() (kymeraAdaptiveAnc_GetChain(CHAIN_MIC_REF_PATH_SPLITTER) != NULL)
#define CONVERT_MSEC_TO_SEC(value) ((value)/1000)
#define IN_EAR TRUE
#define OUT_OF_EAR !IN_EAR
#define ENABLE_ADAPTIVITY TRUE
#define DISABLE_ADAPTIVITY !ENABLE_ADAPTIVITY
#define NUM_STATUS_VAR 24
#define CUR_MODE_STATUS_OFFSET 0
#define FLAGS_STATUS_OFFSET 7
#define FF_GAIN_STATUS_OFFSET 8
#define FLAG_POS_QUIET_MODE 20
#define BIT_MASK(FLAG_POS) (1 << FLAG_POS)
#define AANC_TUNNING_START_DELAY (200U)
/*! Macro for creating messages */
#define MAKE_KYMERA_MESSAGE(TYPE) \
TYPE##_T *message = PanicUnlessNew(TYPE##_T);
#define AANC_TUNING_SINK_USB 0
#define AANC_TUNING_SINK_UNUSED 1 /* Unused */
#define AANC_TUNING_SINK_INT_MIC 2 /* Internal Mic In */
#define AANC_TUNING_SINK_EXT_MIC 3 /* External Mic In */
#define AANC_TUNING_SOURCE_DAC 0
#define AANC_TUNING_SOURCE_UNUSED 1 /* Unused */
#define AANC_TUNING_SOURCE_INT_MIC 2 /* Forwards Int Mic */
#define AANC_TUNING_SOURCE_EXT_MIC 3 /* Forwards Ext Mic */
#ifdef DOWNLOAD_USB_AUDIO
#define EB_CAP_ID_USB_AUDIO_RX CAP_ID_DOWNLOAD_USB_AUDIO_RX
#define EB_CAP_ID_USB_AUDIO_TX CAP_ID_DOWNLOAD_USB_AUDIO_TX
#else
#define EB_CAP_ID_USB_AUDIO_RX CAP_ID_USB_AUDIO_RX
#define EB_CAP_ID_USB_AUDIO_TX CAP_ID_USB_AUDIO_TX
#endif
#ifdef __QCC517X__
/* By default AANC IIR filter sample rate set to 32kHz (in QCC517x devices) */
#define AANC_FILTER_SAMPLE_RATE (adaptive_anc_sample_rate_32khz)
#endif
/* AANC Capability ID*/
/* Hard coded to 0x409F to fix unity. Will be modified*/
#define CAP_ID_DOWNLOAD_AANC_TUNING 0x409F
static kymera_chain_handle_t adaptive_anc_chains[MAX_CHAIN] = {0};
static void kymeraAdaptiveAnc_UpdateAdaptivity(bool enable_adaptivity);
static kymera_chain_handle_t kymeraAdaptiveAnc_GetChain(uint8 index)
{
return ((index < MAX_CHAIN) ? adaptive_anc_chains[index] : NULL);
}
static void kymeraAdaptiveAnc_SetChain(uint8 index, kymera_chain_handle_t chain)
{
if(index < MAX_CHAIN)
adaptive_anc_chains[index] = chain;
}
static Source kymeraAdaptiveAnc_GetOutput(uint8 index, chain_endpoint_role_t output_role)
{
return ChainGetOutput(kymeraAdaptiveAnc_GetChain(index), output_role);
}
static Sink kymeraAdaptiveAnc_GetInput(uint8 index, chain_endpoint_role_t output_role)
{
return ChainGetInput(kymeraAdaptiveAnc_GetChain(index), output_role);
}
static bool IsAancFbcActive;
static bool kymeraAdaptiveAnc_IsAancFbcActive(void)
{
IsAancFbcActive = kymeraAdaptiveAnc_GetChain(CHAIN_FBC) != NULL;
return IsAancFbcActive;
}
/* Mic interface callback functions */
static bool kymeraAdaptiveAnc_MicGetConnectionParameters(uint16 *mic_ids, Sink *mic_sinks, uint8 *num_of_mics, uint32 *sample_rate, Sink *aec_ref_sink);
static bool kymeraAdaptiveAnc_MicDisconnectIndication(const mic_change_info_t *info);
static void kymeraAdaptiveAnc_MicReconnectedIndication(void);
static mic_user_state_t kymeraAdaptiveAnc_GetUserState(void);
static bool kymeraAdaptiveAnc_GetAecRefUsage(void);
/* AANC support functions */
static void kymeraAdaptiveAnc_EnableConcurrency(bool transition);
static void kymeraAdaptiveAnc_CreateEchoCancellerChain(void);
static void kymeraAdaptiveAnc_ConnectConcurrency(void);
static void kymeraAdaptiveAnc_StartConcurrency(bool transition);
static void kymeraAdaptiveAnc_ConnectFbcChain(void);
static void kymeraAdaptiveAnc_ConnectSplitterFbcChain(void);
static void kymeraAdaptiveAnc_ActivateMicRefPathSplitterSecondOutput(void);
static void kymeraAdaptiveAnc_DisableConcurrency(bool transition);
static void kymeraAdaptiveAnc_StopConcurrency(void);
static void kymeraAdaptiveAnc_DisconnectConcurrency(void);
static void kymeraAdaptiveAnc_DestroyConcurrency(bool transition);
static void kymeraAdaptiveAnc_DeactivateMicRefPathSplitterSecondOutput(void);
static void kymeraAdaptiveAnc_DisconnectFbcOutputs(void);
static void kymeraAdaptiveAnc_DisconnectMicRefPathSplitterOutputs(void);
static void kymeraAdaptiveAnc_DisableStandalone(bool transition);
static void kymeraAdaptiveAnc_EnableStandalone(bool transition);
static void kymeraAdaptiveAnc_Stop(void);
static void kymeraAdaptiveAnc_Restart(void);
static void kymeraAdaptiveAnc_Disconnect(void);
static void kymeraAdaptiveAnc_Reconnect(void);
static void kymeraAdaptiveAnc_SetKymeraState(void);
static void kymeraAdaptiveAnc_ResetKymeraState(void);
/**************************************
*** Kymera Mic interface callbacks ***
**************************************/
static uint16 kymera_AdaptiveAncMics[MAX_AANC_MICS] =
{
appConfigAncFeedForwardMic(),
appConfigAncFeedBackMic()
};
static const mic_callbacks_t kymera_AdaptiveAncCallbacks =
{
.MicGetConnectionParameters = kymeraAdaptiveAnc_MicGetConnectionParameters,
.MicDisconnectIndication = kymeraAdaptiveAnc_MicDisconnectIndication,
.MicReconnectedIndication = kymeraAdaptiveAnc_MicReconnectedIndication,
.MicGetUserState = kymeraAdaptiveAnc_GetUserState,
.MicGetAecRefUsage = kymeraAdaptiveAnc_GetAecRefUsage,
};
static const mic_registry_per_user_t kymera_AdaptiveAncRegistry =
{
.user = mic_user_aanc,
.callbacks = &kymera_AdaptiveAncCallbacks,
.permanent.mandatory_mic_ids = &kymera_AdaptiveAncMics[0],
.permanent.num_of_mandatory_mics = MAX_AANC_MICS,
};
/*! For a reconnection the mic parameters are sent to the mic interface.
* return TRUE to reconnect with the given parameters
*/
static bool kymeraAdaptiveAnc_MicGetConnectionParameters(uint16 *mic_ids, Sink *mic_sinks, uint8 *num_of_mics, uint32 *sample_rate, Sink *aec_ref_sink)
{
*sample_rate = AANC_SAMPLE_RATE;
*num_of_mics = MAX_AANC_MICS;
mic_ids[0] = appConfigAncFeedForwardMic();
mic_ids[1] = appConfigAncFeedBackMic();
DEBUG_LOG("kymeraAdaptiveAnc_MicGetConnectionParameters");
if (kymeraAdaptiveAnc_IsAancFbcActive())
{
DEBUG_LOG("AANC concurrency mic sinks");
mic_sinks[0] = kymeraAdaptiveAnc_GetInput(CHAIN_FBC, EPR_AANC_FBC_FF_MIC_IN);
mic_sinks[1] = kymeraAdaptiveAnc_GetInput(CHAIN_FBC, EPR_AANC_FBC_ERR_MIC_IN);
aec_ref_sink[0] = kymeraAdaptiveAnc_GetInput(CHAIN_MIC_REF_PATH_SPLITTER, EPR_SPLT_MIC_REF_IN);
}
else
{
DEBUG_LOG("AANC standalone mic sinks");
mic_sinks[0] = kymeraAdaptiveAnc_GetInput(CHAIN_AANC, EPR_AANC_FF_MIC_IN);
mic_sinks[1] = kymeraAdaptiveAnc_GetInput(CHAIN_AANC, EPR_AANC_ERR_MIC_IN);
aec_ref_sink[0] = NULL;
}
return TRUE;
}
/*! Before the microphones are disconnected, all users get informed with a DisconnectIndication.
* return FALSE: accept disconnection
* return TRUE: Try to reconnect the microphones. This will trigger a kymeraAdaptiveAnc_MicGetConnectionParameters
*/
static bool kymeraAdaptiveAnc_MicDisconnectIndication(const mic_change_info_t *info)
{
DEBUG_LOG("kymeraAdaptiveAnc_MicDisconnectIndication user %d, event %d", info->user, info->event);
/* Stop & disconnect Adaptive ANC audio graph - due to client disconnection request */
kymeraAdaptiveAnc_Stop();
kymeraAdaptiveAnc_Disconnect();
return TRUE;
}
/*! This indication is sent if the microphones have been reconnected after a DisconnectIndication.
* Also used in cases where ANC is enabled and SCO is started, then a kymeraAdaptiveAnc_MicDisconnectIndication
* and a kymeraAdaptiveAnc_MicReconnectedIndication is called, which will configure the new mic sinks through
* kymeraAdaptiveAnc_MicGetConnectionParameters callback from mic framework
*/
static void kymeraAdaptiveAnc_MicReconnectedIndication(void)
{
DEBUG_LOG("kymeraAdaptiveAnc_MicReconnectedIndication");
/* Reconnect & Restart Adaptive ANC audio graph - after new client added */
kymeraAdaptiveAnc_Reconnect();
kymeraAdaptiveAnc_Restart();
}
static mic_user_state_t kymeraAdaptiveAnc_GetUserState(void)
{
return mic_user_state_interruptible;
}
static bool kymeraAdaptiveAnc_GetAecRefUsage(void)
{
return IsAancFbcActive;
}
/***************************************
*** Kymera Output Manager callbacks ***
***************************************/
/*! Notifies registered user that another user is about to connect to the output chain. */
static void kymera_AdaptiveAncOutputConnectingIndication(output_users_t connecting_user, output_connection_t connection_type)
{
UNUSED(connection_type);
UNUSED(connecting_user);
DEBUG_LOG_INFO("kymera_AdaptiveAncOutputConnectingIndication connecting user: enum:output_users_t:%d",connecting_user);
if(kymeraAdaptiveAnc_IsAancActive())
{
if(KymeraAdaptiveAnc_IsConcurrencyActive())
{
/* do nothing */
}
else
{
kymeraAdaptiveAnc_DisableStandalone(TRUE);
kymeraAdaptiveAnc_EnableConcurrency(TRUE);
}
}
}
/*! Notifies registered user that a user has disconnected from the output chain */
static void kymera_AdaptiveAncOutputDisconnectedIndication(output_users_t disconnected_user, output_connection_t connection_type)
{
UNUSED(connection_type);
UNUSED(disconnected_user);
DEBUG_LOG_INFO("kymera_AdaptiveAncOutputDisconnectingIndication disconnected user: enum:output_users_t:%d",disconnected_user);
DEBUG_LOG_INFO("kymera_AdaptiveAncOutputDisconnectingIndication Kymera_OutputIsChainInUse():%d",Kymera_OutputIsChainInUse());
if(!Kymera_OutputIsChainInUse())
{
if(kymeraAdaptiveAnc_IsAancActive())
{
if(KymeraAdaptiveAnc_IsConcurrencyActive())
{