美文网首页代码笔记我爱编程
安卓 录音AudioRecord源码总结

安卓 录音AudioRecord源码总结

作者: _VITA | 来源:发表于2018-05-27 17:19 被阅读13次

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

  • 创建一个数据流。
  • 构造一个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的双向通信机制

相关文章

网友评论

    本文标题:安卓 录音AudioRecord源码总结

    本文链接:https://www.haomeiwen.com/subject/igmsjftx.html