Android Framework源码解读 - Audio - AudioRecord

2021/5/23 20:27:35

本文主要是介绍Android Framework源码解读 - Audio - AudioRecord,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

AudioRecord is a audio client for receiving data from an audio input device such as a microphone.

应用层调用AudioRecord的主要APIs,主要有getMinBufferSize()、new AudioRecord()、startRecording()、getRecordingState()、read()、getState()、stop()、 release(),大致调用步骤如下:

静态方法getMinBufferSize

Java Framework层,./frameworks/base/media/java/android/media/AudioRecord.java

static public int getMinBufferSize(int sampleRateInHz, int channelConfig, int audioFormat) {
    int size = native_get_min_buff_size(sampleRateInHz, channelCount, audioFormat);
}

JNI层, ./frameworks/base/core/jni/android_media_AudioRecord.cpp

static jint android_media_AudioRecord_get_min_buff_size(...) {
    status_t result = AudioRecord::getMinFrameCount(&frameCount,..); 
}

C++ Framework层,./frameworks/av/media/libaudioclient/AudioRecord.cpp 、./frameworks/av/media/libaudioclient/AudioSystem.cpp

status_t AudioRecord::getMinFrameCount(...){
    status_t status = AudioSystem::getInputBufferSize(sampleRate, format, channelMask, &size);
}
AudioSystem 通过binder方式,调用AudioFlinger的getInputBufferSize函数 {
    const sp<AudioFlingerClient> afc = getAudioFlingerClient();
    return afc->getInputBufferSize(sampleRate, format, channelMask, buffSize);
}

new AudioRecord

./frameworks/base/media/java/android/media/AudioRecord.java

throws IllegalArgumentException 调用相关的函数来检查参数的合法性,以及保存参数等操作; 最后调用自己的构造函 this(),一系列操作后走到jni层的方法native_setup();

./frameworks/base/core/jni/android_media_AudioRecord.cpp

./frameworks/av/media/libaudioclient/AudioRecord.cpp

./frameworks/av/media/libaudioclient/AudioSystem.cpp

./frameworks/av/services/audioflinger/AudioFlinger.h

./frameworks/av/services/audioflinger/AudioFlinger.cpp

./frameworks/av/media/libaudioclient/IAudioFlinger.cpp

      

最后是继续通过AudioFlinger去openRecord,这里获取audioflinger对象,使用了了AudioSystem::get_audio_flinger();此方法通过sm->getService()拿到AudioFlinger的实例(Binder Client端)并作为函数返回值af = gAudioFlinger。

为什么说这里获取的是 binder client端呢? 是因为下面这句话:

gAudioFlinger = interface_cast<IAudioFlinger>(binder);

来看看interface_caset<xxx>方法,代码位于 ./frameworks/native/libs/binder/include/binder/IInterface.h, 最终调用的是IAudioFlinger::asInterface();

template<typename INTERFACE>
inline sp<INTERFACE> interface_cast(const sp<IBinder>& obj)
{
    return INTERFACE::asInterface(obj);
}

在IAudioFlinger.cpp里面你会看到一行独立的代码:IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");

按这个IMPLEMENT_META_INTERFACE宏(定义在IInterface.h文件里)展开,就找到了IAudioFlinger::asInterface()方法,最终由它创建了BpAudioFlinger 对象,也就是IAudioFlinger这个接口的binder client对象实例。

另外,还new AudioFlingerClient(), 实例化后会被注册(af->registerClient(afc))到AudioFlinger中;然后afc会通过Binder把服务端与客户端串连起来。  

AudioFlinger对应的Service(服务端运行在audioserver进程中)被创建的时候会调用 SERVICE::getServiceName()  :

这个service name就类似DomainSocket里的PATH。作为binder server端,只要实现onTransact方法。

所以APP调用new AuidoRecord()最终会以Binder Client的形式 告知 audioserver(Binder server),基本流程如下图:

需要注意的一点是:在JNI层有个lpRecored对象,而且有且只有一个,所以同一个应用(进程)只能一个地方调用这个new AudioRecored()。

startRecording 

有了上一节的分析,startRecording的流程也是,app -> java framework -> jni -> c++ framework  (binder client )  < == > audioserver (binder server), 所以先来看看流程图:

status = mAudioRecord->start(event, triggerSession); 这里mAudioRecord对象是在sp<IAudioRecord> record = audioFlinger->openRecord(input,...);时得到的;

查看BpAudioFlinger::openRecord()在从binder server端得到reply后,通过 record = interface_cast<IAudioRecord>(reply.readStrongBinder()); 创建了BpAudioRecord 对象作为接口IAudioRecord的binder client对象实例。

所以接下来看BpAudioRecord的start()函数定义./frameworks/av/media/libaudioclient/IAudioRecord.cpp

同样audioserver端在openRecord()的时候创建了 sp<RecordHandle> recordHandle = new RecordHandle(recordTrack); 它是 BnAudioRecord的实现类。定义在./frameworks/av/services/audioflinger/AudioFlinger.h 实现在./frameworks/av/services/audioflinger/Tracks.cpp, 最后走到recordThread->start();

继续查看recordThread->start, 实现在./frameworks/av/services/audioflinger/Threads.cpp,./frameworks/av/media/libaudioclient/AudioSystem.cpp,./frameworks/av/media/libaudioclient/IAudioPolicyService.cpp

这里AudioSystem::get_audio_policy_service()方法和之前的AudioSystem::get_audio_flinger()一样最终都会得到对应的binder client端,这里就是BpAudioPolicyService,然后发送remote()->transact(START_INPUT..);

./frameworks/av/media/libaudioclient/IAudioPolicyService.cpp,/frameworks/av/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp,./frameworks/av/services/audiopolicy/managerdefault/AudioPolicyManager.cpp

值得注意的一点是:这里Binder IPC机制被用到了同一个进程(audioserver)的两个不同线程(主线程和record thread)之间的通信。

BnAudioPolicyService端最终会调用AudioPolicyManager的startInput函数: status_t status = mAudioPolicyManager->startInput(input, session, &concurrency); 主要工作就是创建相关的audio session并加入AudioSessions管理队列。

read

./frameworks/base/media/java/android/media/AudioRecord.java

BLOCKING方式读取,所以应用层一般要开线程调用read().

./frameworks/base/core/jni/android_media_AudioRecord.cpp

./frameworks/av/media/libaudioclient/AudioRecord.cpp

所以,流程简图总结如下:

这里obtainBuffer()利用了生产者(AudioRecoredServerProxy) - 消费者(AudioRecordClientProxy)模式,从共享内存(IMemory)里面读取数据。

在AudioRecord::openRecord_l()的时候,会得到三个对象,用于共享内存操作;

mCblkMemory = iMem; 
mBufferMemory = bufferMem; 
mProxy = new AudioRecordClientProxy(...);

再来看AduidoRecordServerProxy的创建过程,也是在openRecord的时候创建的,流程如下:

小结

先回顾一下Binder IPC,在AudioRecord和audioserver之间的binder对象主要包括:

binder client类(AudioRecord)  interface(接口类)binder server类(audiorecord)
BpAudioFlingerIAudioFlingerBnAudioFlinger
BpAudioRecordIAudioRecordBnAudioRecord

所谓的Binder IPC,google官方介绍如下:

Binder IPC: The Binder Inter-Process Communication (IPC) mechanism allows the application framework to cross process boundaries and call into the Android system services code. This enables high level framework APIs to interact with Android system services.

B: Binder , n: native ,p: proxy

所以BnInterface是服务端的接口,BpInterface是客户端的代理接口。 Client通过transact()来发送事务请求;而服务端的onTransact()会接收到相应事务。

而binder client的实例对象,一般都是通过interface_caset<xxx> + IMPLEMENT_META_INTERFACE宏这个两个结合来创建的:

IMPLEMENT_META_INTERFACE(AudioFlinger, "android.media.IAudioFlinger");

IMPLEMENT_META_INTERFACE(AudioRecord, "android.media.IAudioRecord");

Binder Driver是个虚拟字符设备(misc设备), 没有硬件,实际是操作一片内存空间。其细节不在这里展开,网络上也有很多文章做细致的介绍。我们只要明白其基本工作原理即可。

 



这篇关于Android Framework源码解读 - Audio - AudioRecord的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程