最近遇到几个与AudioEffect相关的问题,在此记录下作为一个记忆总结

android系统中如果想使用自己开发或者第三方的音效算法,有一种比较简单的办法就是放到hal层的out_write接口中,这样做优点是简单,方便快速集成。还有标准的做法就是做成android标准的音效接口,上层应用就可以像使用android自带的音效一样来调用自己所添加的自定义音效。

如何实现自定义的音效库以及AudioEffect的构造流程分析,已经有不少写的很好的文章,可以参考以下博客

AudioEffect构造流程跟踪 & 音效库实现(native侧)

https://blog.csdn.net/wkw1125/article/details/65632960

Android Effect 解析

https://blog.csdn.net/kuang_tian_you/article/details/83510713

这里主要记录我遇到的几个问题,我看很少有文章讲到,在此做个记录

之前讲到音效集成自己放在hal层或是在送往alsa输出之前做处理这种方法简单同时也能保证系统输出的音频数据都能经过音效算法处理。做成android音效标准接口就有需要注意的地方了,先来看下android audioeffect 处理的地方,在audioflinger的playbackthread中PlaybackThread::threadLoop()

这就意味中必须是meplayer或是audiotrack播放的音频流才能获得音效作用,但是对于一些android TV来说,很多方案商的TV In的音频数据比如HDMI IN、AV IN并不通过audiotrack去播放,例如google专门为android TV设计的TIF架构,走的是audiopatch机制,audio in到 audio out的处理基本上在hal层就干完了,不经过audiotrack 那么如何使用auudioeffect音效呢,这样就能想到如果音效不在audioflinger那一层处理,而是也在hal层去处理,这个功能就完成了。可以看到audioeffect在构造的过程中音效enable时会更新一个状态机

在playbackthread里音效process实时更新状态

EffectModule::updateState中调用start_l(),里面有个接口

可以看到addEffectToHal_l会根据是否有EFFECT_FLAG_TYPE_PRE_PROC和EFFECT_FLAG_TYPE_POST_PROC的flag来判断是否将音效add到hal层

hal层对应实现addEffect这个接口 同时在写到alsa之前调用process即有了音效处理的作用

这就意味着在构造音效库的时候就要指定这些flag,举例如下:

const effect_descriptor_t AvlDescriptor={{0x4a959f5c,0xe33a,0x4df2,0x8c3f,{0x30,0x66,0xf9,0x27,0x5e,0xdf}},{0x08246a2a,0xb2d3,0x4621,0xb804,{0x42,0xc9,0xb4,0x78,0xeb,0x9d}},EFFECT_CONTROL_API_VERSION,EFFECT_FLAG_TYPE_POST_PROC | EFFECT_FLAG_DEVICE_IND | EFFECT_FLAG_NO_PROCESS | EFFECT_FLAG_OFFLOAD_SUPPORTED,AVL_CUP_LOAD_ARM9E,AVL_MEM_USAGE,"Avl","xxxx",
};

EFFECT_FLAG_NO_PROCESS这个flag也很重要,这个flag声明之后 audioflinger那一层将会直接bypass处理不会经过音效作用,具体代码在EffectModule::process()里

同时我们也注意到这个状态机的更新在playbackthread的process loop里,所以创建音效时需要保证playbackthread在running的状态,因为playbackthread在android启动后没有音频播放会进入stabdby状态,所以为了保证音效创建成功,创建的同时可以播放一段空的audiotrack以保证playbackthread是active的。

在这里我们所有的音效都是全局的,即创建音效时指定的sessionId为AUDIO_SESSION_OUTPUT_MIX 这样系统创建一次音效,音效链将会一直绑定在audioflinger上,整个系统将一直有音效作用,而不必像一般内度应用那样创建的时候获取mediaplayer或是audiotrack的sessionId

参数audioSession,相同audioSession ID的AudioTrack和MediaPlayer共享Audio Effect,这是android的接口注释

这里需要注意的是一旦有应用使用非全局的sessionId,并且enable之后会导致我们设置的全局音效被禁用,来看看这部分代码:

进去checkSuspendOnEffectEnabled会调用到

void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled(const sp<EffectModule>& effect,bool enabled,audio_session_t sessionId)
{Mutex::Autolock _l(mLock);checkSuspendOnEffectEnabled_l(effect, enabled, sessionId);
}void AudioFlinger::ThreadBase::checkSuspendOnEffectEnabled_l(const sp<EffectModule>& effect,bool enabled,audio_session_t sessionId)
{if (mType != RECORD) {// suspend all effects in AUDIO_SESSION_OUTPUT_MIX when enabling any effect on// another session. This gives the priority to well behaved effect control panels// and applications not using global effects.// Enabling post processing in AUDIO_SESSION_OUTPUT_STAGE session does not affect// global effectsif ((sessionId != AUDIO_SESSION_OUTPUT_MIX) && (sessionId != AUDIO_SESSION_OUTPUT_STAGE)) {setEffectSuspended_l(NULL, enabled, AUDIO_SESSION_OUTPUT_MIX);}}sp<EffectChain> chain = getEffectChain_l(sessionId);if (chain != 0) {chain->checkSuspendOnEffectEnabled(effect, enabled);}
}

可以看到当sessionId不是全局的时候

void AudioFlinger::ThreadBase::setEffectSuspended_l(const effect_uuid_t *type, bool suspend, audio_session_t sessionId)
{sp<EffectChain> chain = getEffectChain_l(sessionId);if (chain != 0) {if (type != NULL) {chain->setEffectSuspended_l(type, suspend);} else {chain->setEffectSuspendedAll_l(suspend);}}updateSuspendedSessions_l(type, suspend, sessionId);
}

setEffectSuspended_l会disable到其他的音效,所以对于系统集成音效来说,所有音效的使用尽量都使用全局的sessionId

关于AudioEffect使用过程中的构造以及处理流程遇到的几个问题相关推荐

  1. 细数储层预测过程中碰到的的几类采集脚印

    现在储层预测过程中对地震资料的质控越来越严,因为大家都已意识到地震资料品质直接决定了储层预测成果的预测能力与可靠性. 采集脚印(footprint)本意是地震资料采集的专业术语.如果引申一下,对于储层 ...

  2. C++绝不在构造和析构过程中调用virtual函数

    绝不在构造和析构过程中调用virtual函数 如果希望在继承体系中根据类型在构建对象时表现出不同行为,可以会想到在基类的构造函数中调用一个虚函数: class Transaction { //所有交易 ...

  3. 关于构造与析构过程中调用虚函数的问题

    今天面试碰到一个构造函数与析构函数中调用需虚函数的问题,当时不太确定,回来敲了一下,发现确实表现的不一样,在网上一查发现另有玄机. 代码: # gcc version 4.8.2 (Ubuntu 4. ...

  4. Effective C++条款09:绝不在构造和析构过程中调用virtual函数

    Effective C++条款09:绝不在构造和析构过程中调用virtual函数(Never call virtual functions during construction or destruc ...

  5. java中的逸出是什么意思,发布和逸出-构造过程中使this引用逸出

    1.什么是this对象 this就是该对象实例本身 2.何为发布和逸出 发布,就是把对象暴露给他人,这就是为什么会需要用到封装,不能预料到其他第三方会如何使用对象,一不小心可能就被玩坏了 逸出,把不应 ...

  6. OpenCV 相机校正过程中,calibrateCamera函数projectPoints函数的重投影误差的分析

    OpenCV 校正过程中,calibrateCamera函数的ret和重投影误差的分析 OpenCV对相机进行校正的过程中,校正返回值retval和重投影误差的计算公式表示和分析. OpenCV 校正 ...

  7. 类加载过程中几个重点执行顺序整理

    类的加载过程: 1. JVM会先去方法区中找有没有相应类的.class存在.如果有,就直接使用:如果没有,则把相关类的.class加载到方法区 2. 在.class加载到方法区时,会分为两部分加载:先 ...

  8. 中如何构造有参和无惨_CAD制图初学入门:CAD机械软件中如何构造孔?

    在绘制图纸的过程中,如何快速构造不同类型的孔?刚开始进行CAD制图初学入门学习的小伙伴可能对此并不是很了解,那么下面小编就来给大家详细介绍一下构造孔的CAD制图初学入门教程吧! CAD机械软件中构造孔 ...

  9. 关于线程池运行过程中,业务逻辑出现未知异常导致线程中断问题反思

    最近在项目研发中的关于线程池应用过程中由于业务逻辑异常导致的线程中断,但程序未中断导致的脏数据问题  话不多说,在最近最新的一个版本发布过程中,业务需要,我们要定期去给客户预留出可用的资源数据,提供客 ...

最新文章

  1. 云安全趋势:IaaS?谢了,我要 PaaS
  2. QT数据库驱动和多国语言驱动部署注意事项
  3. 在微信小程序中调用本地接口
  4. eclipse再次导入已经逻辑删除的工程,IDE提示已存在,无法导入的解决办法
  5. 清除webkit浏览器css设置滚动条
  6. servlet多线程
  7. 华为p4用鸿蒙系统吗_华为p40pro是鸿蒙系统吗
  8. 在Eclipse中使用SDK中的@hide函数
  9. Spring Batch 4.2.0.M1 发布,批处理应用编写框架
  10. 幂函数c语言递归算法,使用递归的幂函数
  11. burp小技巧之抓单个网站包
  12. 前大灯是近光灯还是远光灯_大灯是近光灯还是远光灯
  13. 谷物调节肠道菌群,促进代谢健康
  14. iot-Scada免费Scada组态软件系列教程4-二次开发与版本部署
  15. 2022-2028全球与中国交通运输锂电池市场现状及未来发展趋势
  16. Windows 7下的Excel 2010同时打开多个独立的窗口 [转]
  17. 遗传算法(GA)的原理简介与应用【python实现】
  18. 64位系统Python注册表问题修复方案
  19. 【应急案例】真实网站劫持案例分析
  20. CSS实现三角形的四种方法

热门文章

  1. 老婆饼就是老婆,会计就是财务
  2. 电脑蜂鸣声,一直滴滴滴叫
  3. struts注解 配置拦截器 拦截器无效
  4. 【转】unity基础问题汇总
  5. 蓝桥杯 Basic--3 字母图形
  6. 人力资源管理系统有哪些推荐?
  7. 4款黑科技级别的宝藏APP,能够轻松满足你的多种需求,请低调收藏
  8. 《JSP实用教程(第2版)/耿祥义》错误之“发呆”时间
  9. java工程加包_向java工程添加jar包
  10. 干度指数NDBSI和湿度WET