[Android] AudioEffect架构:从上层调用到底层音效驱动
来源:互联网 发布:mac os官方下载 编辑:程序博客网 时间:2024/06/06 15:36
- 一上层的API说明
- 二JNI以及配置文件相关文件
- 三交互
- 四音效驱动
- 五分析AudioEffect架构的意图
- 六代码以及控制说明
本篇文章,只研究架构,不谈具体音效的实现算法、
一,上层的API说明
这个可以参考google文档
本地文档路径:
linux_x86/docs/reference/android/media/audiofx/AudioEffect.html
1.AudioEffect不可以直接使用,而需要实现其方法的子类,如Equlizer.java
2,每种音效都对应有一个UUID,具体请查阅AudioEffect.class中间的说明
二,JNI以及配置文件相关文件
源码:
就只有这个目录下面的两个文件:frameworks/base/media/jni/audioeffect/
android_media_Visualizer.cpp
android_media_AudioEffect.cpp
//android_media_AudioEffect.cpp // Dalvik VM type signaturesstatic const JNINativeMethod gMethods[] = { {"native_init", "()V", (void *)android_media_AudioEffect_native_init}, {"native_setup", "(Ljava/lang/Object;Ljava/lang/String;Ljava/lang/String;II[I[Ljava/lang/Object;Ljava/lang/String;)I", (void *)android_media_AudioEffect_native_setup}, {"native_finalize", "()V", (void *)android_media_AudioEffect_native_finalize}, {"native_release", "()V", (void *)android_media_AudioEffect_native_release}, {"native_setEnabled", "(Z)I", (void *)android_media_AudioEffect_native_setEnabled}, {"native_getEnabled", "()Z", (void *)android_media_AudioEffect_native_getEnabled}, {"native_hasControl", "()Z", (void *)android_media_AudioEffect_native_hasControl}, {"native_setParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_setParameter}, {"native_getParameter", "(I[BI[B)I", (void *)android_media_AudioEffect_native_getParameter}, {"native_command", "(II[BI[B)I", (void *)android_media_AudioEffect_native_command}, {"native_query_effects", "()[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryEffects}, {"native_query_pre_processing", "(I)[Ljava/lang/Object;", (void *)android_media_AudioEffect_native_queryPreProcessings},};
音效配置文件audio_effects.conf,可以看到音效的声明格式如下:
# Default pre-processing library. Add to audio_effect.conf "libraries" section if# audio HAL implements support for default software audio pre-processing effects## pre_processing {# path /system/lib/soundfx/libaudiopreprocessing.so# } 说明对应音效的所在库文件# list of effects to load. Each effect element must contain a "library" and a "uuid" element.# The value of the "library" element must correspond to the name of one library element in the# "libraries" element.# The name of the effect element is indicative, only the value of the "uuid" element# designates the effect.# The uuid is the implementation specific UUID as specified by the effect vendor. This is not the# generic effect type UUID.# effects {# <fx name> {# library <lib name># uuid <effect uuid># }# ...# } 这种声明的音效多为指定某一种效果,不需要proxy sw/hw库支持effects {# additions for the proxy implementation# Proxy implementation #effectname { #library proxy #uuid xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx # SW implemetation of the effect. Added as a node under the proxy to # indicate this as a sub effect. #libsw { #library libSW #uuid yyyyyyyy-yyyy-yyyy-yyyy-yyyyyyyyyyyy #} End of SW effect # HW implementation of the effect. Added as a node under the proxy to # indicate this as a sub effect. #libhw { #library libHW #uuid zzzzzzzz-zzzz-zzzz-zzzz-zzzzzzzzzzzz #}End of HW effect #} End of effect proxy 工厂-代理模式,这个比常用,而且较为复杂,下面细说
工厂代理使用音效的模式,调用架构如下
EffectProxyCreate的时候,通过结构体audio_effect_library_t指定具体的操作库,通过音效type指定具体的音效,从而初始化一个EffectContext,返回一个指向EffectContext的handle指针,实际就是effect_interface_s的操作句柄
这里的proxy,bundle,offload_bundle都是使用结构体audio_effect_library_s,名字为AUDIO_EFFECT_LIBRARY_INFO_SYM,声明成一个音效库,
相关结构体说明见最底部
三,交互
分析内容包括:
- 音效架构的初始化
- 根据type和UUID初始化具体的AudioEffect
- 通过setParameter达到上下通信,发送控制信息与接收反馈
创建AudioEffect构造函数分析
status_t AudioEffect::set(const effect_uuid_t *type, const effect_uuid_t *uuid, int32_t priority, effect_callback_t cbf, void* user, audio_session_t sessionId, audio_io_handle_t io){ sp<IEffect> iEffect; sp<IMemory> cblk; int enabled; ALOGV("set %p mUserData: %p uuid: %p timeLow %08x", this, user, type, type ? type->timeLow : 0); if (type == NULL && uuid == NULL) { //需要指定AudioEffect的UUID/type ALOGW("Must specify at least type or uuid"); return BAD_VALUE; } ... ... mDescriptor.type = *(type != NULL ? type : EFFECT_UUID_NULL); mDescriptor.uuid = *(uuid != NULL ? uuid : EFFECT_UUID_NULL); mIEffectClient = new EffectClient(this);//内部类,这个是用来监控当前AudioEffect状态,以及处理控制等消息的,实质还是调用AudioEffect的相关操作函数//还是通过AudioFlinger去创建,操作相关的不同的AudioEffect底层驱动库 iEffect = audioFlinger->createEffect((effect_descriptor_t *)&mDescriptor, mIEffectClient, priority, io, mSessionId, mOpPackageName, &mStatus, &mId, &enabled);... cblk = iEffect->getCblk();//初始化控制单元... mIEffect = iEffect; mCblkMemory = cblk; mCblk = static_cast<effect_param_cblk_t*>(cblk->pointer()); int bufOffset = ((sizeof(effect_param_cblk_t) - 1) / sizeof(int) + 1) * sizeof(int); mCblk->buffer = (uint8_t *)mCblk + bufOffset;... return mStatus;}
往下看AudioFlinger的创建流程:
sp<IEffect> AudioFlinger::createEffect( effect_descriptor_t *pDesc, const sp<IEffectClient>& effectClient, int32_t priority, audio_io_handle_t io, audio_session_t sessionId, const String16& opPackageName, status_t *status, int *id, int *enabled){ status_t lStatus = NO_ERROR; sp<EffectHandle> handle; effect_descriptor_t desc;//忽略检测权限,合法性的判断//1,获取Effect描述符... { if (!EffectIsNullUuid(&pDesc->uuid)) { // if uuid is specified, request effect descriptor //如果给定uuid,则直接获取描述符 lStatus = EffectGetDescriptor(&pDesc->uuid, &desc);... goto Exit; } } else { //如果没有给定uuid,就根据给定的type到effect fectory中间去查找。 // if uuid is not specified, look for an available implementation // of the required type in effect factory ... uint32_t numEffects = 0; effect_descriptor_t d; d.flags = 0; // prevent compiler warning bool found = false;//获取并且遍历所有的音效,这里都是音效工厂提供的API lStatus = EffectQueryNumberEffects(&numEffects); ... }//检查权限之后返回获取的描述符 // return effect descriptor *pDesc = desc;/*2,获取IO,thread,并根据情况创建EffectChain *如果io为null,就调用接口创建一个output,如下 * io =AudioSystem::getOutputForEffect(&desc);获得output * 或者根据seesion_id去所有的threads(play或者record都找)中间查找; * 如果还找不到,就默认使用第一个output * 遍历线程,获得一个线程之后,就创建EffectChain * /... // create effect on selected output thread //2,通过对应线程,创建effectHandle,并且返回 handle = thread->createEffect_l(client, effectClient, priority, sessionId, &desc, enabled, &lStatus, pinned); ...Exit: *status = lStatus; return handle;}
下面通过实际使用音效Equilizer来说明音效调用流程
1,Java调用,创建一个小型播放器,播放一首音乐,期间使用均衡器设置各个频段的声音大小,达到均衡器的作用。APP关键代码如下:
private void setupEqualizerFxAndUI() { //调用MediaPlayer的代码就不在这里说明 // 1,初始化一个均衡器默认使用 priority (0). mEqualizer = new Equalizer(0, mMediaPlayer.getAudioSessionId()); mEqualizer.setEnabled(true); //2,enable这个均衡器 TextView eqTextView = new TextView(this); eqTextView.setText("Equalizer:"); mLinearLayout.addView(eqTextView); short bands = mEqualizer.getNumberOfBands(); //3,获取均衡器支持调节的频段 ,返回5,范围在60~14000HZ,具体查阅hw_sw,高通基线参考equalizer_band_presets_freq[NUM_EQ_BANDS] 路径hardware/qcom/audio/post_proc/equalizer.c final short minEQLevel = mEqualizer.getBandLevelRange()[0]; final short maxEQLevel = mEqualizer.getBandLevelRange()[1]; Log.d(TAG, "getBandLevelRange min:"+minEQLevel+" max:"+maxEQLevel); for (short i = 0; i < bands; i++) { final short band = i; 。。。//4这里主要是根据频bands以及每个band的区间,初始化可操作的seekbar,在事件响应函数中间操作设置参数到底层 frameworks/av/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h freqTextView.setText((mEqualizer.getCenterFreq(band) / 1000) + " Hz"); minDbTextView.setText((minEQLevel / 100) + " dB"); maxDbTextView.setText((maxEQLevel / 100) + " dB"); SeekBar bar = new SeekBar(this); bar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { mEqualizer.setBandLevel(band, (short) (progress + minEQLevel)); //seekbar响应函数中间的具体操作 Log.d(TAG, "seekbar operation: band: "+band+" value:"+(short) (progress + minEQLevel)); } public void onStartTrackingTouch(SeekBar seekBar) {} public void onStopTrackingTouch(SeekBar seekBar) {} }); } }
接下来我们重点关注1,4两个步骤,其他的类似
初始化一个音效
序列图如下:
交互1~17我们在上面已经提及,就不再具体描述,重点记录交互11:EffectCreate,这个函数位于lvm库中间
/* Effect Library Interface Implementation */extern "C" int EffectCreate(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId __unused, effect_handle_t *pHandle){ int ret = 0; int sessionNo; int i; EffectContext *pContext = NULL; bool newBundle = false; SessionContext *pSessionContext; ... pContext = new EffectContext; //此处一大段对pContext的变量赋值,主要是根据uuid找到对应的音效库(sw/hw) if (memcmp(uuid, &gEqualizerDescriptor.uuid, sizeof(effect_uuid_t)) == 0){ // Create Equalizer ALOGV("\tEffectCreate - Effect to be created is LVM_EQUALIZER"); pSessionContext->bEqualizerInstantiated = LVM_TRUE; pContext->pBundledContext->SamplesToExitCountEq = 0; pContext->itfe = &gLvmEffectInterface; pContext->EffectType = LVM_EQUALIZER; } ... *pHandle = (effect_handle_t)pContext; .. return ret;}
操作均衡器中间一个band,根据log和代码分析具体的流程:
V AudioEffect: setParameter: param: 2, param2: 0V Bundle : V Bundle : Effect_command startV Bundle : Effect_command setting command for LVM_EQUALIZERV Bundle : Effect_command INPUTS are: command 5 cmdSize 22V Bundle : Equalizer_command cmdCode Case: EFFECT_CMD_SET_PARAM startV Bundle : Equalizer_setParameter startV Bundle : Equalizer_setParameter() EQ_PARAM_BAND_LEVEL band 0, level -125V Bundle : EqualizerSetBandLevel(-125)->(-1)V Bundle : TOTAL energy estimation: 1.29V Bundle : Vol:-37, GainCorrection: 0, Actual vol: -37V Bundle : Equalizer_setParameter endV Bundle : Effect_command cmdCode Case: EFFECT_CMD_SET_PARAM endV offload_effect_bundle: effect_command: ctxt 0xa67e4500, cmd 5V offload_effect_equalizer: equalizer_set_parameter: ctxt 0xa67e4500, param 2V offload_effect_equalizer: equalizer_set_band_level: ctxt 0xa67e4500, band: 0, level: -125V offload_effect_api: offload_eq_set_preset: preset -1V offload_effect_api: offload_eq_set_bands_levelV offload_effect_api: offload_eq_send_params: flags 0x5 control name :Audio Effects Config 9
从上面的log,就能看清前面提及的proxy->libsw(bundle proxy)->libhw(bundle proxy)->具体音效libhw(offload_effect_equalizer、offload_effect_api)
在这个案例中间,代码的调用流程就不再详细说明,大致流程如下,这个流程能很好的帮助理解EffectChain,EffectModule,EffectHandle ,AudioEffect之间的关系:
//音频数据buffer process()流程:threadbase::threadloop() |-EffectChain::process_l() |_EffectModule::process() |_hw interface process()//控制信息改变的 command流程:AudioFlinger::EffectHandle::command|_EffectModule::command |__hw interface command//当然,配置信息改变,还有如下command调用EffectModule::initEffectModule::configureEffectModule::start_lEffectModule::reset
在均衡器设置band音量的过程中间,最终是调用如下:
effect_command (case EFFECT_CMD_SET_PARAM){ .... case EFFECT_CMD_SET_PARAM: {... *(int32_t *)pReplyData = context->ops.set_parameter(context, p, *replySize);//这个赋值,看后面分析 ....}/* * Effect Library Interface Implementation */int effect_lib_create(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle) {... context->ops.set_parameter = equalizer_set_parameter;//调用这个...}//文件equlizer.c//int equalizer_set_parameter()// |_equalizer_set_band_level// |_offload_eq_send_params 居然是使用mixer接口控制底层!!!int equalizer_set_band_level(equalizer_context_t *context, int32_t band, int32_t level){ ALOGV("%s: ctxt %p, band: %d, level: %d", __func__, context, band, level); if (level > 0) { level = (int)((level+50)/100); } else { level = (int)((level-50)/100); } context->band_levels[band] = level; context->preset = PRESET_CUSTOM; offload_eq_set_preset(&(context->offload_eq), PRESET_CUSTOM); offload_eq_set_bands_level(&(context->offload_eq), NUM_EQ_BANDS, equalizer_band_presets_freq, context->band_levels); if (context->ctl) offload_eq_send_params(context->ctl, context->offload_eq, OFFLOAD_SEND_EQ_ENABLE_FLAG | OFFLOAD_SEND_EQ_BANDS_LEVEL); return 0;} int offload_eq_send_params(struct mixer_ctl *ctl, struct eq_params eq, unsigned param_send_flags){ ... if (param_values[2] && ctl) mixer_ctl_set_array(ctl, param_values, ARRAY_SIZE(param_values));//这里才是重点!!! //通过增加log,查到qcom8909平台,这个mixer info是 “Audio Effects Config 9”可以使用tinymix工具查看这个信息,具体控制的什么呢?这就要开始分析驱动部分了 return 0;}
四,音效驱动
从上一个部分,我们已经分析到,音效libhw实质是会通过pcm/mix接口和底层驱动通信吗,传递控制参数。我们带着如下几个疑问开始分析:
1,Audio Effects Config 9”是如何被赋值的?
2,发送给底层驱动的参数是如何生效的?
1,Audio Effects Config 9”是如何被赋值的?
初始化
static int adev_open(const hw_module_t *module, const char *name, hw_device_t **device){ if (access(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, R_OK) == 0) { adev->offload_effects_lib = dlopen(OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH, RTLD_NOW); if (adev->offload_effects_lib == NULL) { ALOGE("%s: DLOPEN failed for %s", __func__, OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); } else { ALOGV("%s: DLOPEN successful for %s", __func__, OFFLOAD_EFFECTS_BUNDLE_LIBRARY_PATH); adev->offload_effects_start_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, "offload_effects_bundle_hal_start_output");//这个函数中间会给相关ctrl赋值//int (*offload_effects_start_output)(audio_io_handle_t, int); adev->offload_effects_stop_output = (int (*)(audio_io_handle_t, int))dlsym(adev->offload_effects_lib, "offload_effects_bundle_hal_stop_output"); } }}
调用赋值流程
int start_output_stream(struct stream_out *out){ ... adev->offload_effects_start_output(out->handle, out->pcm_device_id);}//offload_effects_start_outputint offload_effects_bundle_hal_start_output(audio_io_handle_t output, int pcm_id){ /* populate the mixer control to send offload parameters */ snprintf(mixer_string, sizeof(mixer_string), "%s %d", "Audio Effects Config", out_ctxt->pcm_device_id); //和使用的pcm id组合成的ctl名字 //这个函数随后将这个effect放到链表,到这里Effect的名字就很清楚了}
2,发送给底层驱动的参数是如何生效的?
这里我们以高通msm8909开始分析,毕竟具体的实现因平台而异,但是大致的原理都是一致的。
看到下面这个文件,这只文件是”Compress Offload platform driver”硬解码platform driver,什么是platform driver,这里需要了解BE、FE,platform,和CPU的关系,这个再其他博客再详细说明,这里就理解为是处理硬解码播放流的驱动就可以了。控制硬解码数据流的传输和路由。
kernel/sound/soc/msm/qdsp6v2/msm-compress-q6-v2.c
下面这一支文件,就是集中处理所有的音效控制信息的,相当公共接口
msm-audio-effects-q6-v2.c
命令声明:
kernel/include/uapi/sound/audio_effects.h
操作band,打印的kernel log信息如下:
[Binder:2541_1 2577] msm_compr_audio_effects_config_put[Binder:2541_1 2577] msm_compr_audio_effects_config_put: Effects supported for compr_type[0][Binder:2541_1 2577] msm_compr_audio_effects_config_put: EQ_MODULE[Binder:2541_1 2577] msm_audio_effects_popless_eq_handler[Binder:2541_1 2577] msm_audio_effects_popless_eq_handler: device: 0[Binder:2541_1 2577] msm_audio_effects_popless_eq_handler: EQ_ENABLE prev:1 new:1[Binder:2541_1 2577] msm_audio_effects_popless_eq_handler: EQ_CONFIG bands:5, pgain:134217728, pset:18[Binder:5349_2 5369] compr_event_handler opcode =000110e8
通过这个log结合代码,我们可以看到的调用流程如下:
//msm-compress-q6-v2.cstatic int msm_compr_audio_effects_config_put(struct snd_kcontrol *kcontrol, struct snd_ctl_elem_value *ucontrol)//(根据control的赋值判断effect—module是EQ_MODULE:){ switch(effect_module): case EQ_MODULE: pr_debug("%s: EQ_MODULE\n", __func__); if (msm_audio_effects_is_effmodule_supp_in_top(effects_module, prtd->audio_client->topology)) msm_audio_effects_popless_eq_handler(prtd->audio_client, &(audio_effects->equalizer), values); break;}//msm-audio-effects-q6-v2.cint msm_audio_effects_popless_eq_handler(struct audio_client *ac, struct eq_params *eq, long *values){for (i = 0; i < num_commands; i++) { switch (command_id) { } } if (params_length && (rc == 0)) q6asm_send_audio_effects_params(ac, params, params_length); //上面根据指令赋值之后,这里开始向ASM发送effect控制参数} //q6asm.c ASM int q6asm_send_audio_effects_params(struct audio_client *ac, char *params, uint32_t params_length){ char *asm_params = NULL; struct apr_hdr hdr; struct asm_stream_cmd_set_pp_params_v2 payload_params; //将pp参数,打包成asm参数,通过apr发出去 rc = apr_send_pkt(ac->apr, (uint32_t *) asm_params);} /*kernel/drivers/soc/qcom/qdsp6v2/apr.c 这个是高通打包的*/int apr_send_pkt(void *handle, uint32_t *buf){ struct apr_svc *svc = handle; struct apr_client *clnt; struct apr_hdr *hdr; uint16_t dest_id; uint16_t client_id; uint16_t w_len; unsigned long flags; clnt = &client[dest_id][client_id]; w_len = apr_tal_write(clnt->handle, buf, hdr->pkt_size);//apr_tal.c /* *实质是调用smd.c "MSM Shared Memory Core" */}
到这里,我们的分析节结束了
五,分析AudioEffect架构的意图
1,集成相关音效方法
2,当出现音质问题时,dump音效处理不同阶段的pcm数据,达到分析数据的目的
3,Android整体架构的理解与掌握
ps:这部分之后有空再补全
六,代码以及控制说明
1,相关代码说明
proxy:
路径 frameworks/av/media/libeffects/proxy/ EffectProxy.cpp
libeffectproxy 实质也是软件音效库
libsw:路径:/frameworks/av/media/libeffects/
data/
downmix/ 音效库libdownmix
factory/ 非音效 音效工厂,共用方法,库libeffects
loudness/ 音效库 libldnhncr
lvm/ 音效,非常重要,包括libmusicbundle libreverb libbundlewrapper libreverbwrapper
preprocessing/ 音效,前处理 libaudiopreprocessing
proxy/
testlibs/ 测试用的
visualizer/ 音效 ibvisualizer
PS:LVM中间包括很多音频数据换算的算法,可以自己研究一下
libhw :hardware/qcom/audio/
post_proc/ 后处理相关
LOCAL_SRC_FILES:= \ bundle.c \ equalizer.c \ bass_boost.c \ virtualizer.c \ reverb.c \ effect_api.cLOCAL_MODULE_RELATIVE_PATH := soundfxLOCAL_MODULE:= libqcompostprocbundle...
visualizer/ 虚拟器的libhw libqcomvisualizer
voice_processing/ 通话后处理 libqcomvoiceprocessing
2,屏蔽所有的音效的开关节点:
PROPERTY_IGNORE_EFFECTS “ro.audio.ignore_effects”
3,相关结构体:
typedef struct output_context_s output_context_t;typedef struct effect_ops_s effect_ops_t;typedef struct effect_context_s effect_context_t;/* effect specific operations. Only the init() and process() operations must be defined. * Others are optional. */typedef struct effect_ops_s { int (*init)(effect_context_t *context); int (*release)(effect_context_t *context); int (*reset)(effect_context_t *context); int (*enable)(effect_context_t *context); int (*disable)(effect_context_t *context); int (*start)(effect_context_t *context, output_context_t *output); int (*stop)(effect_context_t *context, output_context_t *output); int (*process)(effect_context_t *context, audio_buffer_t *in, audio_buffer_t *out); int (*set_parameter)(effect_context_t *context, effect_param_t *param, uint32_t size); int (*get_parameter)(effect_context_t *context, effect_param_t *param, uint32_t *size); int (*command)(effect_context_t *context, uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData);} effect_ops_t;struct effect_context_s { const struct effect_interface_s *itfe; struct listnode effects_list_node; /* node in created_effects_list */ struct listnode output_node; /* node in output_context_t.effects_list */ effect_config_t config; const effect_descriptor_t *desc; audio_io_handle_t out_handle; /* io handle of the output the effect is attached to */ uint32_t state; bool offload_enabled; /* when offload is enabled we process VISUALIZER_CMD_CAPTURE command. Otherwise non offloaded visualizer has already processed the command and we must not overwrite the reply. */ effect_ops_t ops;};
effect_interface_s,就是返回给AudioFlinger操作的句柄。
相关结构体如下:
//hardware/libhardware/include/hardware/audio_effect.h// Effect control interface definitionstruct effect_interface_s { //////////////////////////////////////////////////////////////////////////////// // // Function: process // // Description: Effect process function. Takes input samples as specified // (count and location) in input buffer descriptor and output processed // samples as specified in output buffer descriptor. If the buffer descriptor // is not specified the function must use either the buffer or the // buffer provider function installed by the EFFECT_CMD_SET_CONFIG command. // The effect framework will call the process() function after the EFFECT_CMD_ENABLE // command is received and until the EFFECT_CMD_DISABLE is received. When the engine // receives the EFFECT_CMD_DISABLE command it should turn off the effect gracefully // and when done indicate that it is OK to stop calling the process() function by // returning the -ENODATA status. // // NOTE: the process() function implementation should be "real-time safe" that is // it should not perform blocking calls: malloc/free, sleep, read/write/open/close, // pthread_cond_wait/pthread_mutex_lock... // // Input: // self: handle to the effect interface this function // is called on. // inBuffer: buffer descriptor indicating where to read samples to process. // If NULL, use the configuration passed by EFFECT_CMD_SET_CONFIG command. // // outBuffer: buffer descriptor indicating where to write processed samples. // If NULL, use the configuration passed by EFFECT_CMD_SET_CONFIG command. // // Output: // returned value: 0 successful operation // -ENODATA the engine has finished the disable phase and the framework // can stop calling process() // -EINVAL invalid interface handle or // invalid input/output buffer description //////////////////////////////////////////////////////////////////////////////// int32_t (*process)(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer); //////////////////////////////////////////////////////////////////////////////// // // Function: command // // Description: Send a command and receive a response to/from effect engine. // // Input: // self: handle to the effect interface this function // is called on. // cmdCode: command code: the command can be a standardized command defined in // effect_command_e (see below) or a proprietary command. // cmdSize: size of command in bytes // pCmdData: pointer to command data // pReplyData: pointer to reply data // // Input/Output: // replySize: maximum size of reply data as input // actual size of reply data as output // // Output: // returned value: 0 successful operation // -EINVAL invalid interface handle or // invalid command/reply size or format according to // command code // The return code should be restricted to indicate problems related to this API // specification. Status related to the execution of a particular command should be // indicated as part of the reply field. // // *pReplyData updated with command response // //////////////////////////////////////////////////////////////////////////////// int32_t (*command)(effect_handle_t self, uint32_t cmdCode, uint32_t cmdSize, void *pCmdData, uint32_t *replySize, void *pReplyData); //////////////////////////////////////////////////////////////////////////////// // // Function: get_descriptor // // Description: Returns the effect descriptor // // Input: // self: handle to the effect interface this function // is called on. // // Input/Output: // pDescriptor: address where to return the effect descriptor. // // Output: // returned value: 0 successful operation. // -EINVAL invalid interface handle or invalid pDescriptor // *pDescriptor: updated with the effect descriptor. // //////////////////////////////////////////////////////////////////////////////// int32_t (*get_descriptor)(effect_handle_t self, effect_descriptor_t *pDescriptor); //////////////////////////////////////////////////////////////////////////////// // // Function: process_reverse // // Description: Process reverse stream function. This function is used to pass // a reference stream to the effect engine. If the engine does not need a reference // stream, this function pointer can be set to NULL. // This function would typically implemented by an Echo Canceler. // // Input: // self: handle to the effect interface this function // is called on. // inBuffer: buffer descriptor indicating where to read samples to process. // If NULL, use the configuration passed by EFFECT_CMD_SET_CONFIG_REVERSE command. // // outBuffer: buffer descriptor indicating where to write processed samples. // If NULL, use the configuration passed by EFFECT_CMD_SET_CONFIG_REVERSE command. // If the buffer and buffer provider in the configuration received by // EFFECT_CMD_SET_CONFIG_REVERSE are also NULL, do not return modified reverse // stream data // // Output: // returned value: 0 successful operation // -ENODATA the engine has finished the disable phase and the framework // can stop calling process_reverse() // -EINVAL invalid interface handle or // invalid input/output buffer description //////////////////////////////////////////////////////////////////////////////// int32_t (*process_reverse)(effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer);};//<<<<<<<<<<<<<<<<<<<结构体分界线// Every effect library must have a data structure named AUDIO_EFFECT_LIBRARY_INFO_SYM// and the fields of this data structure must begin with audio_effect_library_ttypedef struct audio_effect_library_s { // tag must be initialized to AUDIO_EFFECT_LIBRARY_TAG uint32_t tag; // Version of the effect library API : 0xMMMMmmmm MMMM: Major, mmmm: minor uint32_t version; // Name of this library const char *name; // Author/owner/implementor of the library const char *implementor; //////////////////////////////////////////////////////////////////////////////// // // Function: create_effect // // Description: Creates an effect engine of the specified implementation uuid and // returns an effect control interface on this engine. The function will allocate the // resources for an instance of the requested effect engine and return // a handle on the effect control interface. // // Input: // uuid: pointer to the effect uuid. // sessionId: audio session to which this effect instance will be attached. // All effects created with the same session ID are connected in series and process // the same signal stream. Knowing that two effects are part of the same effect // chain can help the library implement some kind of optimizations. // ioId: identifies the output or input stream this effect is directed to in // audio HAL. // For future use especially with tunneled HW accelerated effects // // Input/Output: // pHandle: address where to return the effect interface handle. // // Output: // returned value: 0 successful operation. // -ENODEV library failed to initialize // -EINVAL invalid pEffectUuid or pHandle // -ENOENT no effect with this uuid found // *pHandle: updated with the effect interface handle. // //////////////////////////////////////////////////////////////////////////////// int32_t (*create_effect)(const effect_uuid_t *uuid, int32_t sessionId, int32_t ioId, effect_handle_t *pHandle); //////////////////////////////////////////////////////////////////////////////// // // Function: release_effect // // Description: Releases the effect engine whose handle is given as argument. // All resources allocated to this particular instance of the effect are // released. // // Input: // handle: handle on the effect interface to be released. // // Output: // returned value: 0 successful operation. // -ENODEV library failed to initialize // -EINVAL invalid interface handle // //////////////////////////////////////////////////////////////////////////////// int32_t (*release_effect)(effect_handle_t handle); //////////////////////////////////////////////////////////////////////////////// // // Function: get_descriptor // // Description: Returns the descriptor of the effect engine which implementation UUID is // given as argument. // // Input/Output: // uuid: pointer to the effect uuid. // pDescriptor: address where to return the effect descriptor. // // Output: // returned value: 0 successful operation. // -ENODEV library failed to initialize // -EINVAL invalid pDescriptor or uuid // *pDescriptor: updated with the effect descriptor. // //////////////////////////////////////////////////////////////////////////////// int32_t (*get_descriptor)(const effect_uuid_t *uuid, effect_descriptor_t *pDescriptor);} audio_effect_library_t;// Name of the hal_module_info#define AUDIO_EFFECT_LIBRARY_INFO_SYM AELI// Name of the hal_module_info as a string#define AUDIO_EFFECT_LIBRARY_INFO_SYM_AS_STR "AELI"
- [Android] AudioEffect架构:从上层调用到底层音效驱动
- 从上层APP到底层驱动的调用过程
- FM函数从上层到底层调用过程(回顾)
- alarm从上层到底层完整调用流程
- Android手动卸载usb从上层到底层源码分析
- Android 按键处理(驱动层到上层)架构
- 电池电量分析 从上层到底层
- CAMERA流程:从上层到底层
- Camera从上层APP到底层分析
- Camera从上层APP到底层分析
- android底层驱动学习之从应用程序如何到底层driver的调用
- 浅析Linux从API调用到底层驱动的过程
- IT从上层到底层是怎样的学习过程
- android 从顶层到底层 学习笔记--- framework架构
- Android上层APP利用sysfs调用底层驱动分析
- Android Linker(一) 从loadLibrary开始-----上层调用流程
- open系统调用流程--从vfs到底层文件系统
- 从底层到上层添加驱动模块
- MySQL登陆的相关命令
- 【PAT】【Advanced Level】1026. Table Tennis (30)
- FZU Problem 2271 X(最短路)
- 高性能可扩展mysql(执行计划,索引分析优化改写,删除重复数据,区间统计,满查询日志)
- 三分法
- [Android] AudioEffect架构:从上层调用到底层音效驱动
- TensorFlow手写识别
- SPOJ687 Repeats (后缀数组+lcp)
- MathJax基础(2):矩阵
- Realm基础
- php和java之间aes加密的互通
- CCF201312-1 出现次数最多的数 桶排序
- @Cacheable注解在spring3中的使用-实现缓存
- ArrayList源码(2)