Android两种改变音频输出/入设备的方式

目录

一、概述
二、方式一:上层传递参数
三、方式二: 底层改变AudioPolicy
四、总结


一、概述

要想了解Android如何选择音频的输出/入的整个流程,最基本的需要了解清楚AudioPolicy和AudioFinger的功能和关系,以便能够更深入的学习整个Audio框架。
这里只是对实际应用中的功能需求做出方法论。

因为器件测试,OEM功能定制等方面的需求,通常会需要根据不同的usecase来改变最终的输出/入设备。以下给出来两种方式来实现需求,但两种方式各有优劣,笔者最后也会根据自己的工作经历总结不同方式适用的情景。

关于Android Audio系统介绍可以看底部推荐扩展阅读的两个博客,笔者个人觉得很不错。

ps: 如果读者没有做过Android底层的开发也可以做一些了解

二、方式一: 上层传递参数

这种方式可以通过底层的定制为上层提供接口,apk可以直接调用相应的接口来直接达到打开指定的设备的目的。

设计思路:Java层直接使用原生的接口AudioManager.setParameters()向下层传递指定的参数,底层在audio_extn.c中实现相关函数去接收参数,再在手机相应的平台的platform.c中的设置输入/出的函数中调用之前写好的函数即可
整个思路很简单,但是没有实际的例子有说服力。

假定一个功能需求:在录音时,apk传入参数"MIC_CHOOSE=1"使得设备最终使用双麦克录音。

首先,由于是直接调用原生的接口AudioManager.setParameters("MIC_CHOOSE=1")所以我们这里暂且不用关注这个参数是怎么从Java层一直传递下来的,只需要知道Android中可以在hardware/qcom/audio/hal/audio_extn/audio_extn.c中获取所有通过这个接口传递下来的参数,如果使用的是高通平台。

  1. hardware/qcom/audio/hal/audio_extn/audio_extn.h头文件中声明两个函数,用于保存和读取获取到的参数。
//获取保存好的上层传递来的参数
int audio_extn_get_mic_choose_parameters(void); 
//接收并保存上层传来的参数
void audio_extn_set_mic_choose_parameters(struct str_parms *parms);
  1. hardware/qcom/audio/hal/audio_extn/audio_extn.c中实现上面在头文件中声明的两个函数。可是在这之前,要考虑在什么地方去保存我们获取到的参数,以便之后读取呢?
    查看这个C文件后,发现在一个static的结构体audio_extn_module中已经定义了性质相同的一些变量,那么我们也就按照原生的设计逻辑来,在这个结构体中定义变量mic_choose来保存获取的参数。
struct audio_extn_module { 
    ... 
    int mic_choose; 
};

同时需要在对该结构体初始化的地方也对我们定义的变量进行初始化:

static struct audio_extn_module aextnmod = { 
    ... 
    .mic_choose = 0, 
};

紧接着就是对头文件中的两个函数实现:

int audio_extn_get_mic_choose_parameters(void)
{
    ALOGD("%s: mic_choose:%d", __func__, aextnmod.mic_choose);
    return aextnmod.mic_choose;
}
void audio_extn_set_mic_choose_parameters(struct str_parms *parms)
{
    int ret;
    char value[32] = {0};
    ret = str_parms_get_str(parms, "SET_MIC_CHOOSE", value, sizeof(value));
    ALOGD("mic_choose_ret:%d", ret);
    if (ret >= 0) {
        if (strcmp(value, "1") == 0){//接收到的参数为1,表示使用双麦克录音
            aextnmod.mic_choose = 1;
        }
    }
    ALOGD("%s: mic_choose:%d, value:%s", __func__, aextnmod.mic_choose, value);
}

到这里,可能读者会想,要在什么地方去调用上面这个函数去获取传递来的参数呢?Android已经设计好了一个函数,void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms)在其中加入所有需要获取AudioManager.setParameters()传递来的参数的函数,就可以接收我们想要的参数。至于这个函数是谁调用的,何时调用,这里暂不讨论,感兴趣的读者可以自行阅读源码。

void audio_extn_set_parameters(struct audio_device *adev, struct str_parms *parms) { 
    audio_extn_set_anc_parameters(adev, parms);
    audio_extn_set_mic_choose_parameters(parms);//我们自己定义的函数
    audio_extn_set_fluence_parameters(adev, parms);
    audio_extn_set_afe_proxy_parameters(adev, parms);
    audio_extn_fm_set_parameters(adev, parms); 
    ... 
}

以上做的都是准备工作,最后一步,需要在最终选择设备的地方去加入我们的逻辑实现目的。

  1. hardware/qcom/audio/hal/msm8996/platform.c(假设手机使用的是高通的msm8996平台)中在选择输入设备的方法中的录音case中插入我们的代码使得最终使用的设备为双麦克
snd_device_t platform_get_input_snd_device(void *platform, audio_devices_t out_device) { 
    ... 
    else if(source == AUDIO_SOURCE_MIC){//使用mic录音的case
       ... 
       int mic_choose = 0;
       mic_choose = audio_extn_get_mic_choose_parameters(); 
       if (mic_choose == 1){ //将snd_device赋值为双麦克
            snd_device = SND_DEVICE_IN_HANDSET_DMIC;
       } 
         ALOGD("%s: mic_choose (%s)", __func__, device_table[snd_device]); 
    } 
}

这里需要注意,在不同的OEM代码中,对于双麦克定义的设备名称可能会有不同,例如还有定义为SND_DEVICE_IN_HANDSET_STEREO_DMIC的,这里只是一个参考。

三、方式二: 底层改变AudioPolicy(不推荐)

我们知道在什么usecase下要使用什么设备,是由AudioPolicy来决定的,所以,通过改变其中的选择策略可以实现我们的目的。
我们可以在AudioPolicy的核心文件之一Engine.cpp中找到录音的usecase去做相应的改动。

文件路径frameworks/av/services/audiopolicy/enginedefault/src/Engine.cpp

这里需要读者先弄清楚AudioPolicy中strategy的概念,之后再在Engine::getDeviceForStrategyInt()中修改相应的Strategy选择的设备。
这里就不贴代码了,有需求的可以留言。

四、总结

看完了两种修改音频设备的方式,读者心里可能对于两种方式的优劣有了一些想法,笔者在这里只是从工作实践中比较一下两种方式如何取舍:

  • AudioManager.setParameters() 传递参数的方法更为灵活,如果需求有变更,修改代码的量也极小。最大的优点笔者认为有两个:1. 不改动原生的AudioPolicy逻辑,可以很大程度降低因此引起的bug数量; 2. 使用原生的方式就能够为上层提供调用接口,大大降低工作量。
    适用场景: 器件测试,apk特殊需求
  • 修改AudioPolicy的方式如果工程师对整个Policy逻辑不熟悉会很大程度地引起很多莫名其妙的bug,所以笔者并不推荐这种方式。
    适用场景:系统层面的功能需求

写在最后

在实际项目中对于每一个新需求的开发,要养成一个好习惯:
加入项目控制或宏控制!!!
加入项目控制或宏控制!!!
加入项目控制或宏控制!!!
重要的事说三遍!!!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,911评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 82,014评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 142,129评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,283评论 1 264
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,159评论 4 357
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,161评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,565评论 3 382
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,251评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,531评论 1 292
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,619评论 2 310
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,383评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,255评论 3 313
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,624评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,916评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,199评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,553评论 2 342
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,756评论 2 335

推荐阅读更多精彩内容

  • 一.声音参数基本概念: 声音是连续模拟量,计算机将它离散化之后用数字表示,就有了以下几个名词术语。 样本长度(sa...
    cs1001阅读 2,650评论 0 2
  • 提醒一下,纯个人笔记,你完全可能看晕 一、音频数字化基础知识 见书,列出知识点如下: 声音声波,声音频率、响度, ...
    YY17阅读 31,103评论 6 48
  • linux设备模型bus,device,driver作者 codercjg 在 10 十一月 2015, 2:43...
    codercjg阅读 412评论 0 1
  • linux设备模型bus,device,driver作者 codercjg 在 10 十一月 2015, 2:43...
    codercjg阅读 559评论 0 1
  • 在上一篇笔记中我们已经完成了使用SDL播放声音和视频,声音播放没有什么问题,而视频播放太快,很明显视频没有同步。在...
    762683ff5d3d阅读 1,288评论 0 1