aosp15 AudioRecord源码流程分析结合perfetto

背景:

基于aosp15分析录音代码流程,并结合perfetto

应用进程层面分析

AudioRecord() (AudioRecord.java)
–>native_setup
–>android_media_AudioRecord_setup (android_media_AudioRecord.cpp)
–>new AudioRecord
–>lpRecorder->set
–>createRecord_l (AudioRecord.cpp)
–>audioFlinger->createRecord

audioserver层面分析

AudioFlinger::createRecord (AudioFlinger.cpp)
–>AudioSystem::getInputForAttr
–>AudioPolicyService::getInputForAttr
–>AudioPolicyManager::getInputForAttr
–> Engine::getInputDeviceForAttributes
–>getDeviceForInputSource
–>AudioPolicyManager::getInputForDevice
–>getInputProfile
–>new AudioInputDescriptor
–>inputDesc->open
–>mClientInterface->openInput
–>AudioFlinger::openInput (AudioFlinger.cpp)
–>openInput_l
–>findSuitableHwDev_l
–>inHwDev->openInputStream
–> IAfRecordThread::create (Threads.cpp)
–>sp::make
–>mRecordThreads.add
–>thread->createRecordTrack_l (Threads.cpp)
–> IAfRecordTrack::create
–> mTracks.add(track);
–> IAfRecordTrack::createIAudioRecordAdapter(recordTrack) (AudioFlinger.cpp)
–>sp::make

AudioRecord进行start录音

第一次唤醒剖析:

app程序在调用AudioRecord的start方法后就会触发RecordThread进行对应的Track数据读取操作,看代码以为是如下地方进行唤醒的:

status_t RecordThread::start(IAfRecordTrack* recordTrack,
                                           AudioSystem::sync_event_t event,
                                           audio_session_t triggerSession)
{
        recordTrack->setState(IAfTrackBase::STARTING_1);
        mActiveTracks.add(recordTrack);
        if (recordTrack->isExternalTrack()) {
          //调用到apm的startInput
            status = AudioSystem::startInput(recordTrack->portId());
            sendIoConfigEvent_l(
                AUDIO_CLIENT_STARTED, recordTrack->creatorPid(), recordTrack->portId());
        }

    
        recordTrack->setState(IAfTrackBase::STARTING_2);
     //唤醒
        mWaitWorkCV.notify_all();
        return status;
    }
}

再看看RecordThread的运行情况:

bool RecordThread::threadLoop()
{
    

    // loop while there is work to do
    for (int64_t loopCount = 0;; ++loopCount) {  // loopCount used for statistics tracking
        // Note: these sp<> are released at the end of the for loop outside of the mutex() lock.
        sp<IAfRecordTrack> activeTrack;
        std::vector<sp<IAfRecordTrack>> oldActiveTracks;
        Vector<sp<IAfEffectChain>> effectChains;

        // activeTracks accumulates a copy of a subset of mActiveTracks
        Vector<sp<IAfRecordTrack>> activeTracks;

        // reference to the (first and only) active fast track
        sp<IAfRecordTrack> fastTrack;

        // reference to a fast track which is about to be removed
        sp<IAfRecordTrack> fastTrackToRemove;

        bool silenceFastCapture = false;

        { 
        

            // if no active track(s), then standby and release wakelock
            size_t size = mActiveTracks.size();
            if (size == 0) {//这里会判断是否有mActiveTracks然后进入休眠
         
                // go to sleep
                mWaitWorkCV.wait(_l);
       
                goto reacquire_wakelock;
            }
            //省略

上面可以看出在threadLoop中会有判断是否有Active的Track,没有就进行 mWaitWorkCV.wait等待,而上面的start方法刚好也有塞入mActiveTracks中然后进行唤醒。

在这里插入图片描述但是明显这个地方显示的唤醒线程根本不是start那binder线程
在这里插入图片描述
而是:
在这里插入图片描述所以上面分析的代码认为是start方法最后的mWaitWorkCV唤醒是不对的。

那么下面探讨一下为啥会是是ApmAudio [491] 线程呢?
明显可以看出来实际上是sendConfigEvent_l这个方法进行的唤醒,同时结合相关的日志:

04-13 00:46:24.087   369   404 V AudioPolicyService: inserting command: 5 at index 0, num commands 0
04-13 00:46:24.088   369   491 V AudioPolicyService: AudioCommandThread() processing create audio patch
04-13 00:46:24.088   369   491 V AudioFlinger::PatchPanel: createAudioPatch_l() num_sources 1 num_sinks 1 handle 0
04-13 00:46:24.088   369   491 V audio_utils::mutex: mutex_impl: audio_mutex initialized: ret:0  order:20
04-13 00:46:24.088   369   491 V AudioFlinger: sendConfigEvent_l() num events 1 event 3 //有调用sendConfigEvent_l方法而且event值为3
04-13 00:46:24.088   369  2648 V AudioFlinger: RecordThread: loop starting //RecordThread开始运行

看看这个sendConfigEvent_l是如何唤醒的
在这里插入图片描述
下面再来看看触发这个sendConfigEvent_l是如何触发的。
这里看看关键日志
AudioFlinger: sendConfigEvent_l() num events 1 event 3
可以看到这里是 event 3
在这里插入图片描述
可以知道实际上是CFG_EVENT_CREATE_AUDIO_PATCH
frameworks/av/services/audioflinger/Threads.cpp

status_t ThreadBase::sendCreateAudioPatchConfigEvent(
                                                        const struct audio_patch *patch,
                                                        audio_patch_handle_t *handle)
{
    audio_utils::lock_guard _l(mutex());
    sp<ConfigEvent> configEvent = (ConfigEvent *)new CreateAudioPatchConfigEvent(*patch, *handle);
    status_t status = sendConfigEvent_l(configEvent);
    if (status == NO_ERROR) {
        CreateAudioPatchConfigEventData *data =
                                        (CreateAudioPatchConfigEventData *)configEvent->mData.get();
        *handle = data->mHandle;
    }
    return status;
}

而这里的sendCreateAudioPatchConfigEvent调用地方呢?
frameworks/av/services/audioflinger/PatchPanel.cpp
PatchPanel::createAudioPatch_l方法做有调用sendCreateAudioPatchConfigEvent方法

/* Connect a patch between several source and sink ports */
status_t PatchPanel::createAudioPatch_l(const struct audio_patch* patch,
                                   audio_patch_handle_t *handle,
                                   bool endpointPatch)
        //省略
    Patch newPatch{*patch, endpointPatch};
    audio_module_handle_t insertedModule = AUDIO_MODULE_HANDLE_NONE;

    switch (patch->sources[0].type) {
        case AUDIO_PORT_TYPE_DEVICE: {
            // manage patches requiring a software bridge
            // - special patch request with 2 sources (reuse one existing output mix) OR
            // - Device to device AND
            //    - source HW module != destination HW module OR
            //    - audio HAL does not support audio patches creation
            if ((patch->num_sources == 2) ||
                //省略
            } else {
                if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {

                    status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);

那么createAudioPatch_l方法又是哪里调用的呢?
日志中也可以寻找到线索

04-13 00:46:24.088   369   491 V AudioPolicyService: AudioCommandThread() processing create audio patch

到AudioPolicyService.cpp查一下这个日志:
frameworks/av/services/audiopolicy/service/AudioPolicyService.cpp

bool AudioPolicyService::AudioCommandThread::threadLoop()//APM专门有处理command的线程
{
                case CREATE_AUDIO_PATCH: {
                    CreateAudioPatchData *data = (CreateAudioPatchData *)command->mParam.get();
                    ALOGV("AudioCommandThread() processing create audio patch");
                    sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
                    if (af == 0) {
                        command->mStatus = PERMISSION_DENIED;
                    } else {
                        ul.unlock();
                        command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
                        ul.lock();
                    }
                    } break;

可以看出这里通过日志找到后发现就是会调用到AudioFlinger,再调用到

/* Connect a patch between several source and sink ports */
status_t AudioFlinger::createAudioPatch(
        const struct audio_patch* patch, audio_patch_handle_t* handle)
{
    return mPatchPanel->createAudioPatch_l(patch, handle);
}

那么接下来问题又是到底谁发了这个CREATE_AUDIO_PATCH这个command呢?
这里有需要看看创建CREATE_AUDIO_PATCH的方法createAudioPatchCommand被谁调用的。


status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand(
                                                const struct audio_patch *patch,
                                                audio_patch_handle_t *handle,
                                                int delayMs)
{
    sp<AudioCommand> command = new AudioCommand();
    command->mCommand = CREATE_AUDIO_PATCH;

    return status;
}

看看createAudioPatchCommand被谁调用呢?这里就又比较复杂了,直接上上过systrace看看
在这里插入图片描述
这个installPatch方法一路

start方法触发RecordThread运行,systrace总结图留下:

在这里插入图片描述
主要就涉及到了3个线程

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

千里马学框架

帮助你了,就请我喝杯咖啡

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值