Android Soundtrigger唤醒相关时序学习梳理
本文所写内容是在高通芯片平台相关代码基础上学习整理汇总,如有描述不当之处,欢迎指正!
1、SoundTrigger注册唤醒监听事件回调流程(SoundTrigger HAL层到ADSP层,不包括FWK层)
//(1)SoundTriggerSession 回调
vendor/qcom/opensource/audio-hal/st-hal/SoundTriggerSession.cpp
void SoundTriggerSession::GetRecognitionCallback(recognition_callback_t *callback)*callback = rec_callback_;//(2)StartRecognition()接口,关联到 callback
int SoundTriggerSession::StartRecognition(const struct sound_trigger_recognition_config *config,recognition_callback_t callback,void *cookie,uint32_t version)rec_callback_ = callback;//(3)在pal_callback()中调用callback()将存放在sound_trigger_recognition_event 中的数据传递fwkint SoundTriggerSession::pal_callback(pal_stream_handle_t *stream_handle,uint32_t event_id,uint32_t *event_data,uint32_t event_size,uint64_t cookie)struct sound_trigger_recognition_event *st_event = nullptr;
recognition_callback_t callback;
session->GetRecognitionCallback(&callback);callback(st_event, session->GetCookie());//(4)在SoundTriggerDevice()中调用SoundTriggerSession::StartRecognition()
vendor/qcom/opensource/audio-hal/st-hal/SoundTriggerDevice.cpp
static int stdev_start_recognition(const struct sound_trigger_hw_device *dev,sound_model_handle_t sound_model_handle,const struct sound_trigger_recognition_config *config,recognition_callback_t callback,void *cookie)ATRACE_BEGIN("sthal: stdev_start_recognition");
status = st_session->StartRecognition(config, callback, cookie, hw_properties_extended.header.version);//(5)在SoundTriggerDevice::Init()中进行接口初始化
int SoundTriggerDevice::Init(hw_device_t **device, const hw_module_t *module)STHAL_DBG(LOG_TAG, "Register LSM HIDL service");device_->start_recognition = stdev_start_recognition;device_->stop_recognition = stdev_stop_recognition;//(6)SoundTriggerHw开启监听,调用SoundTriggerDevice::start_recognition()
hardware/interfaces/soundtrigger/2.3/default/SoundTriggerHw.cpp
Return<int32_t> SoundTriggerHw::startRecognition(int32_t modelHandle, const V2_0::ISoundTriggerHw::RecognitionConfig& config,const sp<V2_0::ISoundTriggerHwCallback>& /* callback */, int32_t /* cookie */)ret = mHwDevice->start_recognition(mHwDevice, client->getHalHandle(), halConfig,recognitionCallback_, client.get());//(7)SoundTriggerDetector 调用startRecognition()注册回调给到HAL层
frameworks/base/media/java/android/media/soundtrigger/SoundTriggerDetector.java
public boolean startRecognition(@RecognitionFlags int recognitionFlags)
try {status = mSoundTriggerSession.startRecognition(mSoundModel,mRecognitionCallback, new RecognitionConfig(captureTriggerAudio,allowMultipleTriggers, null, null, audioCapabilities),runInBatterySaver);} catch (RemoteException e) {return false;}/*** This class should be constructed by the {@link SoundTriggerManager}.* @hide*/SoundTriggerDetector(ISoundTriggerSession soundTriggerSession,@NonNull GenericSoundModel soundModel,@NonNull Callback callback, @Nullable Handler handler) {mSoundTriggerSession = soundTriggerSession;mSoundModel = soundModel;mCallback = callback;if (handler == null) {mHandler = new MyHandler();} else {mHandler = new MyHandler(handler.getLooper());}mRecognitionCallback = new RecognitionCallback();}事件上报时有两个结构体,一个是sound_trigger_recognition_config,这个是sound_trigger_recognition配置相关的;
还有一个sound_trigger_recognition_event,这个的英文注释如下:Generic recognition event sent via recognition callback。
prebuilts/vndk/v32/arm/include/system/media/audio/include/system/sound_trigger.h
/** configuration for sound trigger capture session passed to start_recognition()*/struct sound_trigger_recognition_config {audio_io_handle_t capture_handle; /* IO handle that will be used for capture.N/A if capture_requested is false */audio_devices_t capture_device; /* input device requested for detection capture */bool capture_requested; /* capture and buffer audio for this recognitioninstance */unsigned int num_phrases; /* number of key phrases recognition extras */struct sound_trigger_phrase_recognition_extra phrases[SOUND_TRIGGER_MAX_PHRASES];/* configuration for each key phrase */unsigned int data_size; /* size of opaque capture configuration data */unsigned int data_offset; /* offset of opaque data start from start of this struct(e.g sizeof struct sound_trigger_recognition_config) */};Generic recognition event sent via recognition callbackstruct __attribute__((aligned(8))) sound_trigger_recognition_event {int status; /* recognition status e.g.RECOGNITION_STATUS_SUCCESS */sound_trigger_sound_model_type_t type; /* event type, same as sound model type.e.g. SOUND_MODEL_TYPE_KEYPHRASE */sound_model_handle_t model; /* loaded sound model that triggered theevent */bool capture_available; /* it is possible to capture audio from thisutterance buffered by theimplementation */int capture_session; /* audio session ID. framework use */int capture_delay_ms; /* delay in ms between end of modeldetection and start of audio availablefor capture. A negative value is possible(e.g. if key phrase is also available forcapture */int capture_preamble_ms; /* duration in ms of audio capturedbefore the start of the trigger.0 if none. */bool trigger_in_data; /* the opaque data is the capture ofthe trigger sound */audio_config_t audio_config; /* audio format of either the trigger inevent data or to use for capture of therest of the utterance */unsigned int data_size; /* size of opaque event data */unsigned int data_offset; /* offset of opaque data start from start ofthis struct (e.g sizeof structsound_trigger_phrase_recognition_event) */};
SoundTriggerDetector调用startRecognition()时将事件监听回调注册到SoundTriggerHal层。
2、高通芯片AudioReach架构芯片平台ADSP层唤醒事件上报流程
唤醒上报事件代码时序(高通AudioReach架构芯片平台)(1)唤醒模块代码上报唤醒事件
capi_wakeup_raise_event_to_dsp_client()me_ptr->cb_info.event_cb(me_ptr->cb_info.event_context,CAPI_EVENT_DATA_TO_DSP_CLIENT_V2, &event_info)CAPI_EVENT_DATA_TO_DSP_CLIENT_V2 = 15(2)capi的callback()回调接口处理此事件消息
gen_topo_capi_cb_handler.c
gen_topo_capi_callback_base(gen_topo_module_t *module_ptr,capi_event_id_t id,capi_event_info_t *event_info_ptr)switch (id)case CAPI_EVENT_DATA_TO_DSP_CLIENT:case CAPI_EVENT_DATA_TO_DSP_CLIENT_V2:return ar_result_to_capi_err(topo_ptr->topo_to_cntr_vtable_ptr->handle_capi_event(module_ptr, id, event_info_ptr));ADSP.HT.5.8/adsp_proc/avs/fwk/spf/containers/spl_cntr/core/src/spl_cntr.c.handle_capi_event = spl_cntr_handle_capi_event,(3)调用spf框架的spl_cntr_handle_capi_event()
ADSP.HT.5.8/adsp_proc/avs/fwk/spf/containers/spl_cntr/core/src/spl_cntr_event_util.c
ar_result_t spl_cntr_handle_capi_event(gen_topo_module_t *module_ptr,capi_event_id_t event_id,capi_event_info_t *event_info_ptr){spl_cntr_t *me_ptr = (spl_cntr_t *)GET_BASE_PTR(spl_cntr_t, topo, module_ptr->topo_ptr);ar_result_t result = AR_EOK;result = cu_handle_capi_event(&me_ptr->cu, &module_ptr->gu, event_id, event_info_ptr);return result;}cu_handle_capi_event()switch (event_id)case CAPI_EVENT_DATA_TO_DSP_CLIENT_V2:{result |= cu_handle_event_data_to_dsp_client_v2_topo_cb(cu_ptr, module_ptr, event_info_ptr);break;}(4)路由到spf框架的cu_handle_event_data_to_dsp_client_v2_topo_cb()接口
ADSP.HT.5.8/adsp_proc/avs/fwk/spf/containers/cmn/container_utils/core/src/cu_utils_island.c
/* Topo callback to handle module event to DSP client v2 */ar_result_t cu_handle_event_data_to_dsp_client_v2_topo_cb(cu_base_t * cu_ptr,gu_module_t * module_ptr,capi_event_info_t *event_info_ptr)capi_event_data_to_dsp_client_v2_t *payload_ptr =(capi_event_data_to_dsp_client_v2_t *)(event_info_ptr->payload.data_ptr);gpr_cmd_alloc_ext_v2_t args;args.heap_index = dest_address.a.gpr_heap_index;args.src_domain_id = dest_address.a.dest_domain_id;args.dst_domain_id = dest_address.a.src_domain_id;args.src_port = module_ptr->module_instance_id;args.dst_port = dest_address.a.src_port;args.token = payload_ptr->token;args.opcode = APM_EVENT_MODULE_TO_CLIENT;args.payload_size = sizeof(apm_module_event_t) + payload_ptr->payload.actual_data_len;args.client_data = 0;args.ret_packet = &event_packet_ptr;result = __gpr_cmd_alloc_ext_v2(&args);//调用gpr接口发送gpr消息给到client端result = __gpr_cmd_async_send(event_packet_ptr);(5)调用gpr接口,为gpr消息申请分配对应的内存大小,
分配原则:先从静态内存池分配,静态分配失败,再从动态内存分配,两者都失败,上报内存分配失败。
ADSP.HT.5.8/adsp_proc/gpr/core/src/gpr_drv_island.c
uint32_t __gpr_cmd_alloc_ext_v2(gpr_cmd_alloc_ext_v2_t *args)rc = __gpr_cmd_alloc_v2(args->payload_size, args->heap_index, &new_packet);uint32_t __gpr_cmd_alloc_v2(uint32_t alloc_size, gpr_heap_index_t heap_index, gpr_packet_t **ret_packet)new_packet = (gpr_packet_t *)gpr_memq_alloc(block);// If packet couldnt not be allocated in static pool, check dynamic poolgpr_allocate_dynamic_packet(&new_packet, packet_size);