android audiorecord

Android Audio

Android是架构分为三层:

底层      Linux Kernel

中间层  主要由C++实现 (Android 60%源码都是C++实现)

应用层  主要由JAVA开发的应用程序

应用程序执行过程大致如下: JAVA应用程序产生操作(播放音乐或停止),然后通过JNI调用进入中间层执行C++代码,中间层处理后可能需要硬件产生动作的,会继续将操作传到Linux Kernel,Kernel ,不需要硬件产生操作的可能在中间层做一些处理就直接返回。需要硬件产生操作的动作则需通过Kernel调用相关的驱动执行动作或一些处理。

在这里大家需要明白一点:Android仅使用了Linux的Kernel ,即便是一些常用的库例如pthread等,都是Android自已用C/C++/汇编重写实现的。

 

因为在音频通路建立过程中,涉及Android IPC通信及系统服务管理,所以下面就这两点先做个简述:

①Android IPC通信采用的是Client/Server结构,Client 客户端 (AudioRecord)通过接口(IAudioRecord)调用Server 服务器对象(AudioFlinger及AudioFlinger::RecordThread等)的方法,并获取执行结果。

AudioRecord.cpp 主要是对类AudioRecord的实现,AudioFlinger.cpp主要是对类AudioFlinger的实现。在底层音频通信中,可以将AudioRecord作为Android IPC通信的客户端,而将AudioFlinger作为服务器端。AudioRecord获取服务器端接口(mAudioRecord)后就可以像执行自已的方法一样调用服务器端方法(AudioFlinger)。

②Android 启动时会创建一个服务管理进程。Android系统中所有的服务都必需注册添加到该进程中,可以通过

sp<IServiceManager> sm=defaultServiceManager()

获取管理进程接口,然后可以通过它的AddService方法将服务注册添加:

sm->addService(String16("media.audio_flinger"), new AudioFlinger());

       只有将服务添加到管理进程中才能被其它的进程使用:

       sp<IServiceManager> sm = defaultServiceManager();

sp<IBinder> binder = sm->getService(String16("media.audio_flinger"));

Android的音频系统在启动的时候会创建两个服务:一个是上面的示例 AudioFlingerService,一个是AudioPolicyService,并添加到管理进程中,之后其它进程可以使用它们提供的方法。

以下简称AudioFlingerService为AudioFlinger, AudioPolicyService为AudioPolicy

 

 

核心流程:

AudioSystem:getinput(…)à

aps->getinput(..)->AudioPolicyService::getInput(…)->

mpPolicyManager->getInput(…)->

<AudioPolicyService>mpClientInterface->openInput(…)

->AudioFlinger::openInput(…)

 

 

下面就以录音为例简单介绍一下底层音频系统里面主要涉及的几个文件:

㈠   Android_audio_input.cpp:

执行上层应用命令(start(),stop(),pause()等)并另启一个线程创建AudioRecord record对象,并调用对象record的start()方法,然后在一个循环中不断读取底层传上来的数据,如下:

while (!iExitAudioThread) {

          ……

              ……

record->read(data,size)      

              ……

              ……

                                          }

㈡   AudioRecord.cpp:

AudioRecord实现类,主要成员 sp<IAudioRecord>   mAudioRecord,在Android_audio_input.cpp中的record的start/read等方法最终调用的是mAudioRecord对应的方法。mAudioRecord成员可以认为是服务器端对象在客户端的一个代理,它的获取也是

sp<IServiceManager> sm = defaultServiceManager();

sp<IBinder> binder= sm->getService(String16("media.audio_flinger"));

sp<IAudioFlinger> audioFlinger = interface_cast<IAudioFlinger>(binder);

先得到服务管理进程接口,然后获取它的”media.audio_flinger”服务。

sp<IAudioRecord> mAudioRecord = audioFlinger->openRecord(getpid(), input,

                                                       sampleRate, format,

                                                       channelCount,

                                                       frameCount,

                                                       ((uint16_t)flags) << 16,

                                                       &status);

这里需要注意,audioFlinger它是IAudioFlinger类型,在Android中大多数以‘I’开头的类大多都是Android IPC通信的客户端接口,也就是说它即将调用的openRecord方法也是服务器端(AudioFlinger类)的方法。通过这个方法可以获得mAudioRecord,大家要看清楚,这个成员也是’I’开头的类型,也就是说它以后调用的方法也是服务器端(AudioFlinger类)的,因此record调用的start/stop等方法转化为mAduioRecord对应的方法,而mAudioRecord是IPC通信的客户端接口(代理),因此最终执行的是服务器端(AudioFlinger)的方法。

㈢   AudioFlinger.cpp:

它是音频通信中的服务器端,主要实现了AudioFlinger类,在此类内部实现了很多内部类,如PlayThread,MixThread,DuplicatingThread,RecordThread等,这些类在音频链路建立过程中是作为服务器端存在的,稍后会详细介绍。

㈣   AudioPolicyManager.cpp:

主要实现AudioPolicyManager类,间接创建RecordThread/PlayThread等,见如下代码(AudioRecord构造函数中一段):

audio_io_handle_t input=

AudioSystem::getInput(inputSource,                                                                             sampleRate, format, channels, (AudioSystem::audio_in_acoustics)flags);

此处会首先通过系统管理进程获取AudioPolicy服务,然后会再次通过Android IPC通信机制,调用服务器端(AudioPolicyManager)的getInput方法。 然后跟进这个方法如下所示:AudioPolicyManager::getInput(…)

       {

              ….

   input = mpClientInterface->openInput(&inputDesc->mDevice,

                                    &inputDesc->mSamplingRate,

                                    &inputDesc->mFormat,

                                    &inputDesc->mChannels,

                                    inputDesc->mAcoustics);

       ….

       }

mpClientInterface->openInput方法继续跟进,会进入AudioFlinger的OpenInput方法

AudioFlinger::OpenInput(…)

{

       …

       thread=

new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);

mRecordThreads.add(mNextThreadId, thread);

       …

     return mNextThreadId;

}

至此,可以看出服务器端的RecordThread是如何创建的,这里先有个概念,顺便指出,这里返回的mNextThreadId就是RecordThread线程的ID。

先看一下Android 音频系统架构

 

 

 

在音频链路建立过程要经过上述三次IPC调用,之后利用共享内存来交互数据,下面详细介绍下链路的建立。

I:

①new AudioRecord(…),创建一个音轨。在其构造函数中会初始化audio_io_handle_t input =AudioSystem::getInput(…),此函数会从系统服务进程处获得AudioPolicy服务引用,该服务是<IAudioPolicyService>类型(它是一个IPC通信客户端代理类),然后再通过Android IPC通信机制,调用服务的远程服务,进入AudioPolicyManager::getInput(…)函数。AudioPolicyManager这个类是远程服务类。

AudioPolicyManager::getInput(…)

{

input = mpClientInterface->openInput(&inputDesc->mDevice,

                                    &inputDesc->mSamplingRate,

                                    &inputDesc->mFormat,

                                    &inputDesc->mChannels,

                                    inputDesc->mAcoustics);

}

在这里mpClientInterface->openInput会将调用一直传到AudioFlinger的openInput方法中。

②AudioFlinger会调用自已的openInput方法:

AudioFlinger::openInput(…)

{

thread = new RecordThread(this, input, reqSamplingRate, reqChannels, ++mNextThreadId);

mRecordThreads.add(mNextThreadId, thread);

Return mNextThreadId;

}

我们可以看到,它创建了RecordThread线程,并自动加入到mRecordThreads(Vector类型)中,并增加线程计数ID,返回RecordThread线程ID。但是在这里需要注意RecordThread还会自动启动thread_loop函数,为什么会这样做呢?因为它间接继承了一个基类RefBase,关于这个分析大家可以查看它的实现,现在只需要知道它在这里会自动调用thread_loop函数。

③AudioFlinger返回的是RecordThread的线程ID,因此客户端调用:

Input= AudioSystem::getInput(…),将会得到服务器端线程ID信息。

④同样是在AudioRecord构造函数中,会初始化sp<IAudioRecord>  mAudioRecord成员。这个成员是AudioRecord类的核心,调用AudioRecord类的方法,最终会调用mAudioRecord成员的方法。从类型上也可以看出,它是一个IPC客户端类,它调用的方法最终还会传到服务器,调用AudioFlinger的方法。

和对input初始化一样,mAudioRecord同样先获取系统服务(AudioFlinger),然后在通过IPC调用,执行服务器端对象方法,然后用返回值初始化mAudioRecord。

const sp<IAudioFlinger>audioFlinger = AudioSystem::get_audio_flinger();

sp<IAudioRecord> record = audioFlinger->openRecord(getpid(), input,

                                                       sampleRate, format,

                                                       channelCount,

                                                       frameCount,

                                                       ((uint16_t)flags) << 16,

                                                       &status);

mAudioRecord=record;

需要注意:audioFlinger和mAudioRecord均是IPC通信客户端接口,它们执行的方法都是服务器的方法。

⑤audioFligner->openRecord调用的就是服务器(AudioFlinger)的方法,这个方法会先根据传入的input(RecordThreadID)查看线程是否存在,然后将客户端(AudioRecord)的线程ID加入到AudioFlinger::RecordThread::mClients中,并创建RecordTrack对象和RecordHandle。

应用程序创建的音轨(AudioRecord录音/AudioTrack放音),在AudioFlinger中都会创建一个对应的Track实例,录音中的实例就是RecordTrack。这个对象在构造时,会创建客户端和服务器端通信用的共享内存,用共享内存可以加快Client/Server数据的传递,C/S交互数据时只需要将共享内存指针返回即可。这样在录音的时候,服务器(AudioFlinger)通过硬件类将读取的数据放入共享内存中,然后唤醒客户端(AudioRecord)取数据,客户端便可利用指针轻松的获取数据。而不是将数据从服务器端再拷贝到客户端。

⑥AudioFlinger返回的对象是RecordHandle,这个类间接继承<IAudioRecord>,因此它会将返回的对象赋值给mAudioRecord。mAudioRecord可以调用getCblk方法返回服务器开辟的内存地址(IMemory接口)。

⑦⑧⑨仍然是一次IPC通信流程,AudioRecord对象调用Start方法-àmAudioRecord.start()通过IPC通信调用服务器端(AudioFlinger:RecordThread)的方法,并将执行结果返回给AudioRecord。

       之后,AudioRecord和AudioFlinger就可以利用共享内存(   audio_track_cbk_t

)交互数据。AudioRecord可以执行上层的命令,stop,pause,reset等并传其传送到服务器端,执行相应动作。至此整个音频通路已建立成功。

本文只是做了个简要介绍一下录音流程通路,如果想了解更多细节请认真分析代码,谢谢。

 

AudioSystem:getinput(…)àaps->getinput(..)->AudioPolicyService::getInput(…)-> mpPolicyManager->getInput(…)-> mpClientInterface->openInput(…)->AudioFlinger::openInput(…)


  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值