DSP

安卓音效AudioEffect源码剖析2——音效库接口

2019-07-13 18:18发布

1、库的导出符号表——audio_effect_library_t

audio_effect_library_t的定义在hardware/libhardware/include/hardware/audio_effect.h中。 这个结构体在Android4.3+时有发生变化,query_num_effects()和query_effect()被删除。 如果希望做库兼容性,需要检测EFFECT_LIBRARY_API_VERSION,当其为 #ifEFFECT_API_VERSION_MAJOR(EFFECT_LIBRARY_API_VERSION) > 2时query_num_effects()和query_effect()不复存在。
typedef 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: query_num_effects // // Description: Returns the number of different effects exposed by the // library. Each effect must have a unique effect uuid (see // effect_descriptor_t). This function together with EffectQueryEffect() // is used to enumerate all effects present in the library. // // Input/Output: // pNumEffects: address where the number of effects should be returned. // // Output: // returned value: 0 successful operation. // -ENODEV library failed to initialize // -EINVAL invalid pNumEffects // *pNumEffects: updated with number of effects in library // //////////////////////////////////////////////////////////////////////////////// int32_t (*query_num_effects)(uint32_t *pNumEffects); //////////////////////////////////////////////////////////////////////////////// // // Function: query_effect // // Description: Returns the descriptor of the effect engine which index is // given as argument. // See effect_descriptor_t for details on effect descriptors. // This function together with EffectQueryNumberEffects() is used to enumerate all // effects present in the library. The enumeration sequence is: // EffectQueryNumberEffects(&num_effects); // for (i = 0; i < num_effects; i++) // EffectQueryEffect(i,...); // // Input/Output: // index: index of the effect // pDescriptor: address where to return the effect descriptor. // // Output: // returned value: 0 successful operation. // -ENODEV library failed to initialize // -EINVAL invalid pDescriptor or index // -ENOSYS effect list has changed since last execution of // EffectQueryNumberEffects() // -ENOENT no more effect available // *pDescriptor: updated with the effect descriptor. // //////////////////////////////////////////////////////////////////////////////// int32_t (*query_effect)(uint32_t index, effect_descriptor_t *pDescriptor); //////////////////////////////////////////////////////////////////////////////// // // 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 at 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;
示例:
__attribute__ ((visibility ("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, name : "Downmix Library", implementor : "The Android Open Source Project", create_effect : DownmixLib_Create, release_effect : DownmixLib_Release, get_descriptor : DownmixLib_GetDescriptor, };
此处定义了创建和销毁的方法,但是作为效果链,怎么可能连个process处理都没有,稍安勿躁。

2、接口定义——effect_handle_t

这里,process和command都出现了。
typedef struct effect_interface_s **effect_handle_t; struct 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 the 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); };

3、定制方法

库导出符号: __attribute__ ((visibility("default"))) audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM = { tag : AUDIO_EFFECT_LIBRARY_TAG, version : EFFECT_LIBRARY_API_VERSION, name : "Downmix Library", implementor : "The Android Open Source Project", create_effect : DownmixLib_Create, release_effect : DownmixLib_Release, get_descriptor : DownmixLib_GetDescriptor, };
库的接口: const struct effect_interface_s gDownmixInterface = { Downmix_Process, Downmix_Command, Downmix_GetDescriptor, NULL /* no process_reverse function, no reference stream needed */ };
库的内部参数:
typedef struct XXX_module_s { const structeffect_interface_s *itfe; XXconfig; } XXX_module_t;
gDownmixInterface的用途,在create_effect中创建XXX_module_t,并设置 module->itfe = &gDownmixInterface; 注意:必须把conststruct effect_interface_s *itfe;作为结构体的第一个元素!