安卓 录音AudioRecord源码总结

一般情况下录音实现的简单流程如下:

  • 创建一个数据流。
  • 构造一个AudioRecord对象,其中需要的最小录音缓存buffer大小可以通过getMinBufferSize方法得到。如果buffer容量过小,将导致对象构造的失败。
  • 初始化一个buffer,该buffer大于等于AudioRecord对象用于写声音数据的buffer大小。
  • 开始录音。
  • 从AudioRecord中读取声音数据到初始化buffer,将buffer中数据导入数据流。
  • 停止录音。
  • 关闭数据流。

Java在创建AudioRecord对象时,会调用native_setup函数,对应native层C++ 中AudioRecord对象调用set

AudioRecord  pAudioRecord  = new android::AudioRecord();    
pAudioRecord->set( inputSource,//并不是资源,实际上是一个定义的枚举;
                                sampleRateInHz,//样本采样频率
                                audioFormat,//采样精度PCM8,PCM16
                                channelConfig,//指定声道数
                                minFrameCount,
                                AudioRecordCallback,//回调
                                NULL,
                                0,
                                true,
                                0,
 android::AudioRecord::TRANSFER_DEFAULT, 
 AUDIO_INPUT_FLAG_NONE, //AUDIO_INPUT_FLAG_NONE //audio_input_flags_t flags);
 NULL
 );

inputSource 的类型定义:

typedef enum {
AUDIO_SOURCE_DEFAULT = 0,
AUDIO_SOURCE_MIC = 1,
AUDIO_SOURCE_VOICE_UPLINK = 2,
AUDIO_SOURCE_VOICE_DOWNLINK = 3,
AUDIO_SOURCE_VOICE_CALL = 4,
AUDIO_SOURCE_CAMCORDER = 5,
AUDIO_SOURCE_VOICE_RECOGNITION = 6,
AUDIO_SOURCE_VOICE_COMMUNICATION = 7,
AUDIO_SOURCE_REMOTE_SUBMIX = 8, / Source for the mix to be presented remotely. /
/ An example of remote presentation is Wifi Display /
/ where a dongle attached to a TV can be used to /
/ play the mix captured by this audio source. /
AUDIO_SOURCE_CNT,
AUDIO_SOURCE_MAX = AUDIO_SOURCE_CNT - 1,
AUDIO_SOURCE_HOTWORD = 1999, / A low-priority, preemptible audio source for
for background software hotword detection.
Same tuning as AUDIO_SOURCE_VOICE_RECOGNITION.
Used only internally to the framework. Not exposed
at the audio HAL. */
} audio_source_t;

在set函数完成三件事:1:进行配置的check;2:获取音频输入操作句柄;3:调用AudioFlinger(AF)处理音频。在openRecord_l()函数创建一个IAudioRecord。

- 2: 调用AudioSystem的方法 与AudioPolicyService跨进程通信

state = AudioSystem::getInputForAttr(&Attr, &input,,,,,,);
//传入input地址,相当于回调,在执行函数的时候将相应数据写入该地址
status_t AudioSystem::getInputForAttr(&Attr, &input,,,,,,){
  const sp<IAudioPolicyService>& aps = AudioSystem::getInputForAttr(&Attr, &input,,,,,,);
  ...
}
//在AudioPolicyInterfaceImpl.cpp里
status_t AudioPolicyService::getInputForAttr(&Attr, &input,,,,,,){
...
return AudioPolicyManager->getInputForAttr(&Attr, &input,,,,,,);
}

在getInputForAttr() ,IAudioPolicyService与AudioPolicyService的实现类AudioPolicyInterfaceImpl进行通信,从而调用到了AudioPolicyManager的getInputForAttr().=>....大致我理解的这部分内容所做的,将传入的input作为key与device传入的mInput进行match,确定输入设备

- 3: AudioRecord与AudioFlinger跨进程通信,创建Bp:IAudioFlinger 命名为audioFlinger.

sp<IAudioRecord> record = audioFlinger->openRecord(input,.....);
//把上面获取的输入句柄input传给AF,以便与在AF中打开输入句柄,在AudioFlinger::openInput中的代码片段,通过音频硬件得到一个音频输入流,接着创建录音线程,并将其添加到录音线程列表中
AudioFlinger::openRecord(input,....){
sp<RecordHanle> recordHandle;
...
//创建RecordTrack
recordTrack = thread ->createRecordTrack_l(input);
//RecordTrack是AF的内部类,开辟了一块共享内存,它的头部是控制块ControlBlock(CB)(audio_track_cblk_t)后面的是缓冲内存,类似与Track,
//该函数返回一个IAudioRecord用于AR 对该内存进行跨进程操作
...
//创建RecordHandle
recordHandle = new RecordHandle(recordTrack);
return recordHandle;
}

这里使用proxy模式,AF返回AR一个RecordHandle,这个RecordHandle以RecordTrack为参数构造。这样一来虽然RecordTrack不能进行基于Binder的通信,但是RecordHandle可以接受远处端的进程请求,然后调用Track的相应函数。RecordHandle是RecordTrack的代理。
将RecordHandle返回给AR之后,AR的 start,stop函数都是通过CB与后面数据缓冲完成数据传递(最终通过memcpy)。

AudioSystem是Audio子系统面向framework层的接口,有AF,AudioPolicyService(APS)的Bn端,也有Bp端。(简单介绍一下:Binder通信,Bp端向ServiceManager(句柄为0)获取Bn端的句柄,通过句柄找到Bn端,通过Binder通信让Bn端做事)
具体看图

AudioSystem和AudioFliger以及AudioPolicyService的双向通信机制


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

推荐阅读更多精彩内容