ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

Android Framework源码解读 - Audio - AudioRecord

2021-05-23 18:29:44  阅读:933  来源: 互联网

标签:frameworks media AudioRecord Framework binder 源码 av cpp


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设备), 没有硬件,实际是操作一片内存空间。其细节不在这里展开,网络上也有很多文章做细致的介绍。我们只要明白其基本工作原理即可。

 

标签:frameworks,media,AudioRecord,Framework,binder,源码,av,cpp
来源: https://blog.csdn.net/lzqustc/article/details/117197263

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有