audio_effect介绍
audio_effect简介
模块介绍
audio_effect模块是用来做音频效果的,音效流程分为以下部分:
1.audiorenderer:音效的应用入口,提供napi。
2.audioeffect:创建音效链设置效果模式。
3.AudioService:处理分布式音频服务的音效添加事件
4.model:HDF层中加载音效配置和创建音效控制器
5.mockeffect:音效库的调用用于模拟音效。
6.libmock_effect_lib:音效库
整体结构如图
音效整体框图
audio_effect运行
入口通过napi调用GetAudioEffectMode和start的接口运行。
start部分
开始音频播放,从源文件中读取音频信息,创建音效链,最后进行播放。
音效流程
预置音效查询功能都封装在PresetEffect
* 在选择框中的类型和场景映射为数字后, 作为之后调用的getAudioEffectInfoArray(content type:number, stream usage:number)的两个入参
* 点击”查询“按钮后, 使用audio.getAudioManager()获取音频管理对象audioManager, 再通过audioManager.getStreamManager()对象获取audioStreamManager
* 使用audioStreamManager.getAudioEffectInfoArray()获取当前的预置音效模式, api返回数字, 映射后显示在查询结果一栏
实时音效设置功能都封装在RealtimeEffect
点击播放调用createAudioRenderer(audioRendererOptions),其中的audioRendererOptions使用了在选择框中的类型和场景映射成的数字
使用audioRenderer.start()方法和audioRenderer.write()进行音频的播放处理, 写入字节的长度由audioRenderer.getBufferSize()接口来决定
使用resourceManager.getRawFd()接口加载工程里面的resources\rawfile下面的音频文件资源获取对应的文件描述对象fileDescriptor
使用audioRenderer.pause()方法暂停音频流, 使用audioRenderer.stop()和audioRenderer.release()方法释放当前audioRenderer
点击查询按钮, 调用audioRenderer.getAudioEffectMode()方法查询当前音频流的音效模式, 显示在查询结果内
点击”音频流音效模式设置“选项, 调用audioRenderer.setAudioEffectMode()方法,设置要用的音效模式
通过三个选择框的更新, audioRenderer的state和播放按钮状态的监视, 来触发UI状态的更新
调用组件的.enabled(enabled: boolean)方法控制其置灰与使能
AudioEffect关键代码分享
getAudioEffectInfoArray
获取当前音效模式的信息。使用callback异步回调。
napi_value NapiAudioStreamMgr::GetEffectInfoArray(napi_env env, napi_callback_info info)
{
auto context = std::make_shared();
if (context == nullptr) {
AUDIO_ERR_LOG("GetEffectInfoArray failed : no memory");
NapiAudioError::ThrowError(env, "GetEffectInfoArray failed : no memory", NAPI_ERR_NO_MEMORY);
return NapiParamUtils::GetUndefinedValue(env);
}
auto inputParser = [env, context](size_t argc, napi_value *argv) {
NAPI_CHECK_ARGS_RETURN_VOID(context, argc >= ARGS_ONE, "invalid arguments", NAPI_ERR_INPUT_INVALID);
context->status = NapiParamUtils::GetValueInt32(env, context->streamUsage, argv[PARAM0]);
NAPI_CHECK_ARGS_RETURN_VOID(context, context->status == napi_ok, "getstreamUsage failed",
NAPI_ERR_INPUT_INVALID);
if (!NapiAudioEnum::IsLegalInputArgumentStreamUsage(context->streamUsage)) {
context->SignError(NAPI_ERR_INVALID_PARAM);
}
};
context->GetCbInfo(env, info, inputParser);
if ((context->status != napi_ok) && (context->errCode == NAPI_ERR_INPUT_INVALID)) {
NapiAudioError::ThrowError(env, context->errCode);
return NapiParamUtils::GetUndefinedValue(env);
}
auto executor = [context]() {
CHECK_AND_RETURN_LOG(CheckContextStatus(context), "context object state is error.");
auto obj = reinterpret_cast<NapiAudioStreamMgr*>(context->native);
ObjectRefMap objectGuard(obj);
auto *napiStreamMgr = objectGuard.GetPtr();
CHECK_AND_RETURN_LOG(CheckAudioStreamManagerStatus(napiStreamMgr, context),
"context object state is error.");
StreamUsage streamUsage = static_cast<StreamUsage>(context->streamUsage);
context->intValue = napiStreamMgr->audioStreamMngr_->GetEffectInfoArray(
context->audioSceneEffectInfo, streamUsage);
NAPI_CHECK_ARGS_RETURN_VOID(context, context->intValue == SUCCESS, "GetEffectInfoArray failed",
NAPI_ERR_SYSTEM);
};
auto complete = [env, context](napi_value &output) {
NapiParamUtils::SetEffectInfo(env, context->audioSceneEffectInfo, output);
};
return NapiAsyncWork::Enqueue(env, context, "GetEffectInfoArray", executor, complete);
}
StartAudioStream
用于启动音频流。
bool AudioStream::StartAudioStream(StateChangeCmdType cmdType)
{
CHECK_AND_RETURN_RET_LOG((state_ == PREPARED) || (state_ == STOPPED) || (state_ == PAUSED),
false, "Illegal state:%{public}u", state_);
CHECK_AND_RETURN_RET_LOG(!isPausing_, false,
"Illegal isPausing_:%{public}u", isPausing_);
int32_t ret = StartStream(cmdType); //尝试启动音频流
CHECK_AND_RETURN_RET_LOG(ret == SUCCESS, false, "StartStream Start failed:%{public}d", ret);
resetTime_ = true;
int32_t retCode = clock_gettime(CLOCK_MONOTONIC, &baseTimestamp_);
if (retCode != 0) {
AUDIO_ERR_LOG("AudioStream::StartAudioStream get system elapsed time failed: %d", retCode);
}
isFirstRead_ = true;
isFirstWrite_ = true;
state_ = RUNNING;
//根据renderMode_(渲染模式)和captureMode_(捕获模式)的值,决定是否需要启动读写线程。
if (renderMode_ == RENDER_MODE_CALLBACK) {
if (writeThread_ && writeThread_->joinable()) {
writeThread_->join();
}
isReadyToWrite_ = true;
writeThread_ = std::make_uniquestd::thread(&AudioStream::WriteCbTheadLoop, this);
pthread_setname_np(writeThread_->native_handle(), "OS_AudioWriteCb");
} else if (captureMode_ == CAPTURE_MODE_CALLBACK) {
isReadyToRead_ = true;
readThread_ = std::make_uniquestd::thread(&AudioStream::ReadCbThreadLoop, this);
pthread_setname_np(readThread_->native_handle(), "OS_AudioReadCb");
}
AUDIO_INFO_LOG("StartAudioStream SUCCESS, sessionId: %{public}d", sessionId_);
if (audioStreamTracker_ && audioStreamTracker_.get()) {
AUDIO_DEBUG_LOG("AudioStream:Calling Update tracker for Running");
audioStreamTracker_->UpdateTracker(sessionId_, state_, GetClientPid(), rendererInfo_, capturerInfo_);
}
OpenDumpFile();
return true;
}
EffectChainManagerCreateCb
动态创建一个音频效果链
int32_t EffectChainManagerCreateCb(const char *sceneType, const char *sessionID)
{
AudioEffectChainManager *audioEffectChainManager = AudioEffectChainManager::GetInstance();
CHECK_AND_RETURN_RET_LOG(audioEffectChainManager != nullptr, ERR_INVALID_HANDLE, "null audioEffectChainManager");
std::string sceneTypeString = "";
std::string sessionIDString = "";
if (sceneType) {
sceneTypeString = sceneType;
}
if (sessionID) {
sessionIDString = sessionID;
}
if (!audioEffectChainManager->CheckAndAddSessionID(sessionIDString)) {
return SUCCESS;
}
//音频处理是否支持硬件卸载
if (audioEffectChainManager->GetOffloadEnabled()) {
audioEffectChainManager->RegisterEffectChainCountBackupMap(sceneTypeString, "Register");
return SUCCESS;
}
//创建一个音频效果链
if (audioEffectChainManager->CreateAudioEffectChainDynamic(sceneTypeString) != SUCCESS) {
return ERROR;
}
return SUCCESS;
}
AddEffectHandle
用于向音频效果链中添加一个效果处理器,初始化、启用、配置效果处理器,并设置特定的参数。
void AudioEffectChain::AddEffectHandle(AudioEffectHandle handle, AudioEffectLibrary *libHandle)
{
int32_t ret;
int32_t replyData = 0;
AudioEffectTransInfo cmdInfo = {sizeof(AudioEffectConfig), &ioBufferConfig};
AudioEffectTransInfo replyInfo = {sizeof(int32_t), &replyData};
ret = (*handle)->command(handle, EFFECT_CMD_INIT, &cmdInfo, &replyInfo);
CHECK_AND_RETURN_LOG(ret == 0, "[%{public}s] with mode [%{public}s], either one of libs EFFECT_CMD_INIT fail",
sceneType.c_str(), effectMode.c_str());
ret = (*handle)->command(handle, EFFECT_CMD_ENABLE, &cmdInfo, &replyInfo);
CHECK_AND_RETURN_LOG(ret == 0, "[%{public}s] with mode [%{public}s], either one of libs EFFECT_CMD_ENABLE fail",
sceneType.c_str(), effectMode.c_str());
ret = (*handle)->command(handle, EFFECT_CMD_SET_CONFIG, &cmdInfo, &replyInfo);
CHECK_AND_RETURN_LOG(ret == 0, "[%{public}s] with mode [%{public}s], either one of libs EFFECT_CMD_SET_CONFIG fail",
sceneType.c_str(), effectMode.c_str());
// Set param
AudioEffectParam *effectParam = new AudioEffectParam[sizeof(AudioEffectParam) +
NUM_SET_EFFECT_PARAM * sizeof(int32_t)];
effectParam->status = 0;
effectParam->paramSize = sizeof(int32_t);
effectParam->valueSize = 0;
int32_t *data = &(effectParam->data[0]);
*data++ = EFFECT_SET_PARAM;
*data++ = GetKeyFromValue(AUDIO_SUPPORTED_SCENE_TYPES, sceneType);
*data++ = GetKeyFromValue(AUDIO_SUPPORTED_SCENE_MODES, effectMode);
cmdInfo = {sizeof(AudioEffectParam) + sizeof(int32_t) * NUM_SET_EFFECT_PARAM, effectParam};
ret = (*handle)->command(handle, EFFECT_CMD_SET_PARAM, &cmdInfo, &replyInfo);
delete[] effectParam;
CHECK_AND_RETURN_LOG(ret == 0, "[%{public}s] with mode [%{public}s], either one of libs EFFECT_CMD_SET_PARAM fail",
sceneType.c_str(), effectMode.c_str());
standByEffectHandles.emplace_back(handle);
libHandles.emplace_back(libHandle);
}
AudioManagerImplGetInstance
尝试加载音频管理器所需的动态库(声音降噪,回声消除)
struct IAudioManager *AudioManagerImplGetInstance(void)
{
struct AudioManagerPriv *priv = GetAudioManagerPriv();
int32_t ret = AudioManagerLoadPrimaryLib(priv);
if (ret != HDF_SUCCESS) {
HDF_LOGE("%{public}s:Audio manager load lib failed, ret[%{public}d]", __func__, ret);
return NULL;
}
if (priv->createIfInstance == NULL) {
HDF_LOGE("%{public}s:Audio manager createIfInstance is NULL", __func__);
dlclose(priv->handle);
priv->handle = NULL;
return NULL;
}
struct IAudioManager *interface = priv->createIfInstance();
if (interface == NULL) {
HDF_LOGE("%{public}s:call createIfInstance fail", __func__);
dlclose(priv->handle);
priv->handle = NULL;
return NULL;
}
return interface;
}
AudioInitDynamicLib
用于初始化音频相关的动态库和处理器
static int32_t AudioInitDynamicLib(void)
{
if (g_capturePassthroughPath == NULL || g_renderPassthroughPath == NULL) {
AUDIO_FUNC_LOGE("sopath is error");
return AUDIO_ERR_INTERNAL;
}
//初始化音频捕获处理器
int32_t ret = InitCapturePassthroughHandle(g_capturePassthroughPath);
if (ret < 0) {
AUDIO_FUNC_LOGE("InitCapturePassthroughHandle FAIL!");
return AUDIO_ERR_INTERNAL;
}
//初始化音频渲染处理器
ret = InitRenderPassthroughHandle(g_renderPassthroughPath);
if (ret < 0) {
AUDIO_FUNC_LOGE("InitRenderPassthroughHandle FAIL!");
AudioDlClose(&g_ptrCaptureHandle);
return AUDIO_ERR_INTERNAL;
}
//初始化音频效果处理器
ret = InitEffectPassthroughHandle(g_effectPassthroughPath);//待实现
if (ret < 0) {
AUDIO_FUNC_LOGE("InitEffectPassthroughHandle FAIL!");
AudioDlClose(&g_ptrEffectHandle);
return AUDIO_ERR_INTERNAL;
}
#ifndef AUDIO_HAL_NOTSUPPORT_PATHSELECT
ret = InitPathSelectPassthroughHandle(g_pathSelectPassthroughPath);
if (ret < 0 || g_pathSelGetConfToJsonObj == NULL) {
AUDIO_FUNC_LOGE("InitPathSelectPassthroughHandle FAIL!");
AudioDlClose(&g_ptrRenderHandle);
AudioDlClose(&g_ptrCaptureHandle);
return AUDIO_ERR_INTERNAL;
}
ret = g_pathSelGetConfToJsonObj();
if (ret < 0) {
AUDIO_FUNC_LOGE("g_pathSelGetConfToJsonObj FAIL!");
AudioDlClose(&g_ptrRenderHandle);
AudioDlClose(&g_ptrCaptureHandle);
AudioDlClose(&g_ptrPathSelHandle);
return AUDIO_ERR_INTERNAL;
}
#endif
return AUDIO_SUCCESS;
}
InitEffectPassthroughHandle(初步实现)
static int32_t InitEffectPassthroughHandle(const char *effectPassthroughPath)
{
if (effectPassthroughPath == NULL) {
AUDIO_FUNC_LOGE("effectPassthroughPath is NULL");
return HDF_FAILURE;
}
char pathBuf[PATH_MAX] = {'\0'};
if (realpath(effectPassthroughPath, pathBuf) == NULL) {
return HDF_FAILURE;
}
if (g_ptrEffectHandle == NULL) {
g_ptrEffectHandle = dlopen(pathBuf, RTLD_LAZY);
if (g_ptrEffectHandle == NULL) {
AUDIO_FUNC_LOGE("open lib effect so fail, reason:%{public}s", dlerror());
return HDF_FAILURE;
}
AUDIO_FUNC_LOGE("open lib effect so success");
g_bindServiceEffect = dlsym(g_ptrEffectHandle, "MockCreateController");//映射MockCreateController函数
g_interfaceLibModeEffect = dlsym(g_ptrEffectHandle, "MockDestroyController");//映射MockDestroyController函数
g_closeServiceEffect = dlsym(g_ptrEffectHandle, "MockGetDescriptor");//映射MockGetDescriptor函数
if (g_getAllCardInfo == NULL) {
g_getAllCardInfo = dlsym(g_ptrEffectHandle, "AudioGetAllCardInfo");
}
if (g_bindServiceEffect == NULL || g_interfaceLibModeEffect == NULL || g_closeServiceEffect == NULL) {
AUDIO_FUNC_LOGE("lib render so func not found!");
AudioDlClose(&g_ptrEffectHandle);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
audio_effect适配
MockEffectProcess的实现:MockEffect到libmock_effect_lib未实现,需要打开libmock_effect_lib库,在 MockEffectProcess中调用libmock_effect_lib中的EffectProcess接口,以及interface层(*createEffect)到HDF层的接口调用。
static int32_t MockEffectProcess(struct IEffectControlVdi *self, const struct AudioEffectBufferVdi *input,
struct AudioEffectBufferVdi *output)
{
if (self == NULL || input == NULL || output == NULL) {
HDF_LOGE("%{public}s: invailid input params", func);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
struct AudioEffectLibrary {
uint32_t version;
const char *name;
const char *implementor;
bool (*checkEffect) (const AudioEffectDescriptor descriptor);
int32_t (*createEffect) (const AudioEffectDescriptor descriptor, AudioEffectHandle *handle);
int32_t (*releaseEffect) (AudioEffectHandle handle);
};
MockEffectReverse
static int32_t MockEffectReverse(struct IEffectControlVdi *self, const struct AudioEffectBufferVdi *input,
struct AudioEffectBufferVdi *output)
{
if (self == NULL || input == NULL || output == NULL) {
HDF_LOGE("%{public}s: invailid input params", func);
return HDF_ERR_INVALID_PARAM;
}
return HDF_SUCCESS;
}
实现AudioInitDynamicLib对libmock_effect_lib库初始化音频效果处理器
static const char *g_effectPassthroughPath = HDF_LIBRARY_FULL_PATH("libmock_effect_lib");//增加libmock_effect_lib路径
static int32_t AudioInitDynamicLib(void)
{
if (g_capturePassthroughPath == NULL || g_renderPassthroughPath == NULL) {
AUDIO_FUNC_LOGE("sopath is error");
return AUDIO_ERR_INTERNAL;
}
int32_t ret = InitCapturePassthroughHandle(g_capturePassthroughPath);
if (ret < 0) {
AUDIO_FUNC_LOGE("InitCapturePassthroughHandle FAIL!");
return AUDIO_ERR_INTERNAL;
}
ret = InitRenderPassthroughHandle(g_renderPassthroughPath);
if (ret < 0) {
AUDIO_FUNC_LOGE("InitRenderPassthroughHandle FAIL!");
AudioDlClose(&g_ptrCaptureHandle);
return AUDIO_ERR_INTERNAL;
}
//增加初始化音频效果处理器
ret = InitEffectPassthroughHandle(g_effectPassthroughPath);
if (ret < 0) {
AUDIO_FUNC_LOGE("InitEffectPassthroughHandle FAIL!");
AudioDlClose(&g_ptrEffectHandle);
return AUDIO_ERR_INTERNAL;
}
#ifndef AUDIO_HAL_NOTSUPPORT_PATHSELECT
ret = InitPathSelectPassthroughHandle(g_pathSelectPassthroughPath);
if (ret < 0 || g_pathSelGetConfToJsonObj == NULL) {
AUDIO_FUNC_LOGE("InitPathSelectPassthroughHandle FAIL!");
AudioDlClose(&g_ptrRenderHandle);
AudioDlClose(&g_ptrCaptureHandle);
return AUDIO_ERR_INTERNAL;
}
ret = g_pathSelGetConfToJsonObj();
if (ret < 0) {
AUDIO_FUNC_LOGE("g_pathSelGetConfToJsonObj FAIL!");
AudioDlClose(&g_ptrRenderHandle);
AudioDlClose(&g_ptrCaptureHandle);
AudioDlClose(&g_ptrPathSelHandle);
return AUDIO_ERR_INTERNAL;
}
#endif
return AUDIO_SUCCESS;
}
InitEffectPassthroughHandle
用于初始化音频效果动态库,映射动态库中MockCreateController函数
static int32_t InitEffectPassthroughHandle(const char *effectPassthroughPath)
{
if (effectPassthroughPath == NULL) {
AUDIO_FUNC_LOGE("effectPassthroughPath is NULL");
return HDF_FAILURE;
}
char pathBuf[PATH_MAX] = {'\0'};
if (realpath(effectPassthroughPath, pathBuf) == NULL) {
return HDF_FAILURE;
}
if (g_ptrEffectHandle == NULL) {
g_ptrEffectHandle = dlopen(pathBuf, RTLD_LAZY);
if (g_ptrEffectHandle == NULL) {
AUDIO_FUNC_LOGE("open lib effect so fail, reason:%{public}s", dlerror());
return HDF_FAILURE;
}
AUDIO_FUNC_LOGE("open lib effect so success");
g_bindServiceEffect = dlsym(g_ptrEffectHandle, "MockCreateController");//映射MockCreateController函数
g_interfaceLibModeEffect = dlsym(g_ptrEffectHandle, "MockDestroyController");//映射MockDestroyController函数
g_closeServiceEffect = dlsym(g_ptrEffectHandle, "MockGetDescriptor");//映射MockGetDescriptor函数
if (g_getAllCardInfo == NULL) {
g_getAllCardInfo = dlsym(g_ptrEffectHandle, "AudioGetAllCardInfo");
}
if (g_bindServiceEffect == NULL || g_interfaceLibModeEffect == NULL || g_closeServiceEffect == NULL) {
AUDIO_FUNC_LOGE("lib render so func not found!");
AudioDlClose(&g_ptrEffectHandle);
return HDF_FAILURE;
}
}
return HDF_SUCCESS;
}
编译生成的pac文件,烧录到开发者手机。运行idl_render可执行文件,根据hilog打印信息进行调试。
hilog
推送一个音频文件到板子上
hdc_std file send F:\single_short2.wav /data
用idl_render运行
./idl_render /data/single_short2.wav
音效测试
编译测试程序
./build.sh --product-name oriole –ccache --build-target --fast-rebuild
将测试程序和音乐文件推送到板子上
hdc file send F:\audio_sample_render /data
hdc file send F:\single_short2.wav /data
修改测试文件权限
hdc shell chmod 777 /data/idl_render
运行测试程序
./data/idl_render /data/single_short2.wav
选择primary->service loading->start->non-mmap
附代码路径
audiorenderer
foundation/multimedia/audio_framework/frameworks/native/audiorenderer
audio_service路径
foundation/multimedia/audio_framework/services/audio_service
pulseaudio
foundation/multimedia/audio_framework/frameworks/native/pulseaudio
audioeffect路径
foundation/multimedia/audio_framework/frameworks/native/audioeffect
model路径
drivers/peripheral/audio/effect/model
mock_effect路径
drivers/peripheral/audio/effect/model/src/mock_effect
更多推荐
所有评论(0)