最近遇到几个与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. Science:又一明星菌群可以调控肠道免疫?
  2. 简易无接触温度测量与身份识别装置【2020年大学生电子设计竞赛F题】
  3. ai人工智能python开发_Python才是人工智能AI的首选编程语言,你值得拥有……
  4. 小程序和APP的差别是什么?
  5. 马斯克:2020 年底将完成 L5 级别自动驾驶功能
  6. Java从入门到精通 第17章 对象的引用与传递
  7. Linux的Netfilter框架深度思考-对比Cisco的ACL
  8. python维度切片中三个是怎么取值的_总结python 多维切片之冒号和三个点的使用方法...
  9. Linux虚拟机的安装与创建【超详细】【手把手教学】
  10. MemTest64内存测试
  11. win7下安装最新版nodejs16.4.0
  12. 面板数据熵值法-Python
  13. 苹果手机突然闪退的7个原因及修复方法
  14. 哔哩哔哩作者页上的作品批量保存的方法
  15. 爬虫实战-爬取豆瓣读书书籍信息
  16. 【学习笔记】Python基础入门知识笔记,万字攻略带你走进Python编程
  17. 光线追踪渲染实战(四):微平面理论与迪士尼 BRDF,严格遵循物理!
  18. 苹果登陆代理方法didCompleteWithAuthorization没有调用,didCompleteWithError没有走
  19. 如何彻底解决顽固mysql
  20. 内核earlyprintk选项

热门文章

  1. 世界最小量子计算机诞生,离子阱量子技术或成为最终赢家?
  2. Android变成setContentView()报错空指针异常
  3. 华为认证网络工程师认证考试笔试题
  4. 用Go语言开发一个编程语言
  5. 1.1 Go语言简介
  6. java实验Employee_java实验报告5
  7. jquery ready vue_JQuery、Vue等考点
  8. 【cocos3.x+tilemap】制作rpg小游戏(一)地图制作
  9. zynqsd的读写数据_【正点原子FPGA连载】 第十二章SD卡读写TXT文本实验-摘自【正点原子】领航者 ZYNQ 之嵌入式开发指南 (amobbs.com 阿莫电子论坛)...
  10. 人生苦短,我学Python-008:程序设计方法学