Android 5.1 Audio系统笔记:AudioRecord

前言

还是绕不开录音部分,最近想了解一下重采样的内容,但是毫无头绪,硬着头皮先把AudioRecord熟悉一遍先。牵涉到audioflinger这块都是弯弯绕绕的,Are you ready ?

AudioTrack

AudioTrack,录音部分的核心,往简单的说无非以下几部分:
1、AudioRecord的创建:创建相应的线程
2、AudioRecord音频路由建立
3、开始读数据

第一部分:AudioRecord创建

从frameworks/base/media/java/android/media/AudioRecord.java开始
new AudioRecord();

//frameworks/base/core/jni/android_media_AudioRecord.cpp
public AudioRecord(AudioAttributes attributes, AudioFormat format, int bufferSizeInBytes,
        int sessionId) throws IllegalArgumentException {
	1.标记mRecordingState为stoped状态;
    2.获取一个MainLooper;
    3.判断录音源是否是REMOTE_SUBMIX,有兴趣的童鞋可以深入研究;
    4.重新获取rate与format参数,这里会根据AUDIO_FORMAT_HAS_PROPERTY_X来判断从哪里获取参数,而在之前的构造函数中,设置参数的时候已经标记了该标志位,所以这两个参数还是我们设置的;
    5.调用audioParamCheck对参数再一次进行检查合法性;
    6.获取声道数以及声道掩码,单声道掩码为0x10,双声道掩码为0x0c7.调用audioBuffSizeCheck检查最小缓冲区大小是否合法;
    8. 调用native_setup的native函数 ,注意这里传过去的参数包括:指向自己的指针,录制源,rate,声道掩码,format,minBuffSize,session[]9.标记mRecordingState为inited状态;
        注:关于SessionId
             一个Session就是一个会话,每个会话都有一个独一无二的Id来标识。该Id的最终管理在AudioFlinger中。
             一个会话可以被多个AudioTrack对象和MediaPlayer共用。
             共用一个Session的AudioTrack和MediaPlayer共享相同的AudioEffect(音效)
}

8.1 native_setup

//frameworks/base/core/jni/android_media_AudioRecord.cpp
static jint
android_media_AudioRecord_setup(JNIEnv *env, jobject thiz, jobject weak_this,
        jobject jaa, jint sampleRateInHertz, jint channelMask,
                // Java channel masks map directly to the native definition
        jint audioFormat, jint buffSizeInBytes, jintArray jSession)
{
	8.1.1.判断声道掩码是否合法,然后通过掩码计算出声道数;
    8.1.2.由于最小缓冲区大小是采样帧数量*每个采样帧大小得出,每个采样帧大小为所有声道数所占的字节数,从而求出采样帧数量frameCount;
    8.1.3.进行一系列的JNI处理录音源,以及把AudioRecord.java的指针绑定到lpCallbackData回调数据中,
    这样就能把数据通过回调的方式通知到上层;
    8.1.4.调用AudioRecord的set函数(lpRecorder->set),这里注意下flags,他的类型为audio_input_flags_t,
    定义在system\core\include\system\audio.h中,
    作为音频输入的标志,这里设置为AUDIO_INPUT_FLAG_NONE
typedef enum {
    AUDIO_INPUT_FLAG_NONE       = 0x0,  // no attributes
    AUDIO_INPUT_FLAG_FAST       = 0x1,  // prefer an input that supports "fast tracks"
    AUDIO_INPUT_FLAG_HW_HOTWORD = 0x2,  // prefer an input that captures from hw hotword source
} audio_input_flags_t;
    8.1.5.把lpRecorder对象以及lpCallbackData回调保存到javaAudioRecordFields的相应字段中
}

8.1.4 set

frameworks\av\media\libmedia\AudioRecord.cpp
status_t AudioRecord::set(
        audio_source_t inputSource,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t frameCount,
        callback_t cbf,
        void* user,
        uint32_t notificationFrames,
        bool threadCanCallJava,
        int sessionId,
        transfer_type transferType,
        audio_input_flags_t flags,
        const audio_attributes_t* pAttributes)
{
	8.1.4.1.在JNI中传递过来的参数:transferType为TRANSFER_DEFAULT,cbf!=null,threadCanCallJava=true,
	所以mTransfer设置为TRANSFER_SYNC,他是决定如何从AudioRecord传输数据方式,后面会用到;
    8.1.4.2.保存相关的参数,如录制源mAttributes.source,采样率mSampleRate,采样精度mFormat,
    声道掩码mChannelMask,声道数mChannelCount,采样帧大小mFrameSize,采样帧数量mReqFrameCount,
    通知帧计数mNotificationFramesReq,mSessionId在这里更新了,
    音频输入标志mFlags还是之前的AUDIO_INPUT_FLAG_NONE
    8.1.4.3.当cbf数据回调函数不为null时,开启一个录音线程AudioRecordThread;
	8.1.4.4.调用openRecord_l(0)创建IAudioRecord对象;
	8.1.4.5.如果建立失败,就销毁录音线程AudioRecordThread,否则更新参数;
}
8.1.4.4 创建IAudioRecord对象 openRecord_l
//frameworks\av\media\libmedia\AudioRecord.cpp
status_t AudioRecord::openRecord_l(size_t epoch){
	8.1.4.4.1.获取IAudioFlinger对象,其通过binder和AudioFlinger通信,所以也就是相当于直接调用到AudioFlinger服务中了;
    8.1.4.4.2.判断音频输入标志,是否需要清除AUDIO_INPUT_FLAG_FAST标志位,这里不需要,一直是AUDIO_INPUT_FLAG_NONE;
    8.1.4.4.3.调用AudioSystem::getInputForAttr获取输入流的句柄input;
    8.1.4.4.4.调用audioFlinger->openRecord创建IAudioRecord对象;
    8.1.4.4.5.通过IMemory共享内存,获取录音数据;
    8.1.4.4.6.更新AudioRecordClientProxy客户端代理的录音数据;
}
8.1.4.4.3 getInputForAttr
//frameworks\av\media\libmedia\AudioSystem.cpp
status_t AudioSystem::getInputForAttr(const audio_attributes_t *attr,
                                audio_io_handle_t *input,
                                audio_session_t session,
                                uint32_t samplingRate,
                                audio_format_t format,
                                audio_channel_mask_t channelMask,
                                audio_input_flags_t flags)
{
    const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
    if (aps == 0) return NO_INIT;
    return aps->getInputForAttr(attr, input, session, samplingRate, format, channelMask, flags);
}

8.1.4.4.3.1 AudioPolicyService::getInputForAttr
frameworks\av\services\audiopolicy\AudioPolicyInterfaceImpl.cpp
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags)
{
	8.1.4.4.3.1.1.对source为HOTWORD或FM_TUNER的录音源,判断是否具有相应的录音权限(根据应用进程号)8.1.4.4.3.1.2.继续调用AudioPolicyManager的方法(AudioPolicyManager::getInputForAttr)获取input以及inputType;
    8.1.4.4.3.1.3.检查应用是否具有该inputType的录音权限;
    8.1.4.4.3.1.4.判断是否需要添加音效(audioPolicyEffects),需要则使用audioPolicyEffects->addInputEffects添加音效;
}
8.1.4.4.3.1.2 AudioPolicyManager::getInputForAttr
//frameworks\av\services\audiopolicy\AudioPolicyManager.cpp
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
                                             audio_io_handle_t *input,
                                             audio_session_t session,
                                             uint32_t samplingRate,
                                             audio_format_t format,
                                             audio_channel_mask_t channelMask,
                                             audio_input_flags_t flags,
                                             input_type_t *inputType)
{
	8.1.4.4.3.1.2.1.调用getDeviceAndMixForInputSource函数获取policyMix设备以及对应的audio_device_t设备类型(device)
	8.1.4.4.3.1.2.2.获取inputType的类型
	8.1.4.4.3.1.2.3.更新channelMask,适配声道到输入源;
    8.1.4.4.3.1.2.4.调用getInputProfile,根据传进来的采样率/精度/掩码等参数与获得的设备支持的Input Profile比较,
    返回一个与设备Profile匹配的IOProfile对象,IOProfile是用来描述输出或输入流的能力,
    策略管理器使用它来确定输出或输入是否适合于给定的用例, 相应地打开/关闭它,以及连接/断开音频轨道;
    8.1.4.4.3.1.2.5.如果获取失败的话,则使用AUDIO_INPUT_FLAG_NONE再次获取一遍,如果依然失败,则return一个bad news;
    8.1.4.4.3.1.2.6.继续调用mpClientInterface->openInput建立起输入流;
    8.1.4.4.3.1.2.7.根据IOProfile对象构造AudioInputDescriptor,并绑定到input流中,最后更新AudioPortList;
}
8.1.4.4.3.1.2.1.调用getDeviceAndMixForInputSource

首先看下AudioPolicyManager.cpp::getInputForAttr()的第1步.获取policyMix设备以及对应的audio_device_t设备类型(device)

audio_devices_t AudioPolicyManager::getDeviceAndMixForInputSource(audio_source_t inputSource,
                                                            AudioMix **policyMix)
{
   这里就是通过InputSource去获取相应的policyMix与audio_device_t设备类型了,
   从这里也可以看出Android系统上对Audio设备的分类有多少种了。
}

类似AudioTrack的音频策略找到相应的设备类型,这里就是录音的策略了。

8.1.4.4.4 audioFlinger->openRecord
//frameworks\av\services\audiopolicy\AudioPolicyClientImpl.cpp
status_t AudioPolicyService::AudioPolicyClient::openInput(audio_module_handle_t module,
                                                          audio_io_handle_t *input,
                                                          audio_config_t *config,
                                                          audio_devices_t *device,
                                                          const String8& address,
                                                          audio_source_t source,
                                                          audio_input_flags_t flags)
{
    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
    if (af == 0) {
        ALOGW("%s: could not get AudioFlinger", __func__);
        return PERMISSION_DENIED;
    }
 
    return af->openInput(module, input, config, device, address, source, flags);
}

8.1.4.4.4.1 AudioFlinger::openInput

这里就调用到了AF端的openInput函数了

//frameworks\av\services\audioflinger\AudioFlinger.cpp
status_t AudioFlinger::openInput(audio_module_handle_t module,
                                          audio_io_handle_t *input,
                                          audio_config_t *config,
                                          audio_devices_t *device,
                                          const String8& address,
                                          audio_source_t source,
                                          audio_input_flags_t flags)
{
	8.1.4.4.4.1.1.findSuitableHwDev_l中通过IOProfile中的module.handle与audio_device_t设备类型找到Hw模块;

    8.1.4.4.4.1.2.调用HAL层inHwHal->open_input_stream打开输入流;

    8.1.4.4.4.1.3.如果失败了,再继续调用一次;

    8.1.4.4.4.1.4.根据inHwDev与inStream创建AudioStreamIn对象,如此,就建立起了一个输入流了,
    AudioStreamIn定义在frameworks\av\services\audioflinger\AudioFlinger.h;

    8.1.4.4.4.1.5.创建一个RecordThread线程,并把该线程加入到mRecordThreads线程中,
    这个线程是在AudioRecord.cpp::set()函数中创建的;
}

8.1.4.4.4.1.2 调用HAL层 open_input_stream
//hardware\aw\audio\tulip\audio_hw.c
static int adev_open_input_stream(struct audio_hw_device *dev,
                                  audio_io_handle_t handle,
                                  audio_devices_t devices,
                                  struct audio_config *config,
                                  struct audio_stream_in **stream_in)
{
	1.检查rate,format,channel参数是否支持;

    2.给sunxi_stream_in输入流对象分配内存空间;

    3.绑定相应参数的获取/设置方法;

    4.为输入流创建buff空间:in->config.period_size *audio_stream_frame_size(&in->stream.common) * 85.如果是AUDIO_DEVICE_IN_AF类型的设备的话,则对PcmManager做相应处理;
}

这个输入流对象会绑定到AF中的AudioStreamIn对象中,所以到这里,输入流对象就已经完全创建好了。

8.1.4.4.4.1.5 创建一个RecordThread线程
//frameworks\av\services\audioflinger\Threads.cpp
udioFlinger::RecordThread::RecordThread(const sp<AudioFlinger>& audioFlinger,
                                         AudioStreamIn *input,
                                         audio_io_handle_t id,
                                         audio_devices_t outDevice,
                                         audio_devices_t inDevice
#ifdef TEE_SINK
                                         , const sp<NBAIO_Sink>& teeSink
#endif
                                         ) :
    ThreadBase(audioFlinger, id, outDevice, inDevice, RECORD),
    mInput(input), mActiveTracksGen(0), mRsmpInBuffer(NULL),
    // mRsmpInFrames and mRsmpInFramesP2 are set by readInputParameters_l()
    mRsmpInRear(0)
#ifdef TEE_SINK
    , mTeeSink(teeSink)
#endif
    , mReadOnlyHeap(new MemoryDealer(kRecordThreadReadOnlyHeapSize,
            "RecordThreadRO", MemoryHeapBase::READ_ONLY))
    // mFastCapture below
    , mFastCaptureFutex(0)
    // mInputSource
    // mPipeSink
    // mPipeSource
    , mPipeFramesP2(0)
    // mPipeMemory
    // mFastCaptureNBLogWriter
    , mFastTrackAvail(false)
{
	1.调用readInputParameters_l函数把录音参数读取到线程空间中;
    2.创建AudioStreamInSource对象,作为线程中间中的输入流,其实现是在frameworks\av\media\libnbaio\AudioStreamInSource.cpp
}
8.1.4.4 调用 thread->createRecordTrack_l创建IAudioRecord对象
sp<IAudioRecord> AudioFlinger::openRecord(
        audio_io_handle_t input,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t *frameCount,
        IAudioFlinger::track_flags_t *flags,
        pid_t tid,
        int *sessionId,
        size_t *notificationFrames,
        sp<IMemory>& cblk,
        sp<IMemory>& buffers,
        status_t *status)
{
	1.调用recordingAllowed检查录音权限;

    2.判断参数是否非法;

    3.调用checkRecordThread_l函数,根据input从AudioRecordThread线程中获取该input的RecordThread,在前面的分析中可以得知,这个RecordThread是在AudioFlinger.cpp::openInput函数中创建并添加到AudioRecordThread中的;

    4.调用createRecordTrack_l方法创建一个RecordTrack对象,RecordThread::RecordTrack对象的作用是管理RecordThread中的音频数据;

    5.通过SessionId获取是否存在effect chain,若有,则加到RecordThread中;

    6.通过RecordTrack获取cblk以及buffers,他们就是CblkMemory以及BufferMemory;

    7.根据recordTrack,创建RecordHandle对象,实现位置:frameworks\av\services\audioflinger\Tracks.cpp,也就完成了IAudioRecord对象的创建了,也就是说IAudioRecord的方法是在Tracks.cpp中实现的;
}

调用createRecordTrack_l方法创建一个RecordTrack对象
sp<AudioFlinger::RecordThread::RecordTrack> AudioFlinger::RecordThread::createRecordTrack_l(
        const sp<AudioFlinger::Client>& client,
        uint32_t sampleRate,
        audio_format_t format,
        audio_channel_mask_t channelMask,
        size_t *pFrameCount,
        int sessionId,
        size_t *notificationFrames,
        int uid,
        IAudioFlinger::track_flags_t *flags,
        pid_t tid,
        status_t *status)
{
	这个函数重要的一点就是重新计算了frameCount大小,然后根据新的参数创建了RecordTrack对象,然后return}
当应用层new AudioRecord时,系统建立起了输入流,并创建了RecordThread线程,现在录音的准备工作已经完成,就等待应用层开启录音了。

本文是整理得出:https://www.cnblogs.com/pngcui/p/10016538.html ,
然鹅是5.1的跟9.0千差万别。。。。。。。。。。。。下一篇基于Android9.0的,,,正在重新整理校验中。。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值