• (三)Audio子系统之AudioRecord.startRecording


    在上一篇文章《(二)Audio子系统之new AudioRecord()》中已经介绍了Audio系统如何创建AudioRecord对象以及输入流,并创建了RecordThread线程,接下来,继续分析AudioRecord方法中的startRecording的实现

      

      函数原型:

         public void startRecording() throws IllegalStateException

           作用:

        开始进行录制

      参数:

        无

      返回值:

        无

          异常:

        若没有初始化完成时,抛出IllegalStateException

    接下来进入系统分析具体实现

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

        public void startRecording()
        throws IllegalStateException {
            if (mState != STATE_INITIALIZED) {
                throw new IllegalStateException("startRecording() called on an "
                        + "uninitialized AudioRecord.");
            }
    
            // start recording
            synchronized(mRecordingStateLock) {
                if (native_start(MediaSyncEvent.SYNC_EVENT_NONE, 0) == SUCCESS) {
                    handleFullVolumeRec(true);
                    mRecordingState = RECORDSTATE_RECORDING;
                }
            }
        }

    首先判断是否已经初始化完毕了,在前一篇文章中,mState已经是STATE_INITIALIZED状态了。所以继续分析native_start函数

    frameworks/base/core/jni/android_media_AudioRecord.cpp

    static jint
    android_media_AudioRecord_start(JNIEnv *env, jobject thiz, jint event, jint triggerSession)
    {
        sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
        if (lpRecorder == NULL ) {
            jniThrowException(env, "java/lang/IllegalStateException", NULL);
            return (jint) AUDIO_JAVA_ERROR;
        }
    
        return nativeToJavaStatus(
                lpRecorder->start((AudioSystem::sync_event_t)event, triggerSession));
    }

    继续往下:lpRecorder->start

    frameworksavmedialibmediaAudioRecord.cpp

    status_t AudioRecord::start(AudioSystem::sync_event_t event, int triggerSession)
    {
        AutoMutex lock(mLock);
        if (mActive) {
            return NO_ERROR;
        }
    
        // reset current position as seen by client to 0
        mProxy->setEpoch(mProxy->getEpoch() - mProxy->getPosition());
        // force refresh of remaining frames by processAudioBuffer() as last
        // read before stop could be partial.
        mRefreshRemaining = true;
    
        mNewPosition = mProxy->getPosition() + mUpdatePeriod;
    	
        int32_t flags = android_atomic_acquire_load(&mCblk->mFlags);
    
        status_t status = NO_ERROR;
        if (!(flags & CBLK_INVALID)) {
            ALOGV("mAudioRecord->start()");
            status = mAudioRecord->start(event, triggerSession);
            if (status == DEAD_OBJECT) {
                flags |= CBLK_INVALID;
            }
        }
        if (flags & CBLK_INVALID) {
            status = restoreRecord_l("start");	
        }
    
        if (status != NO_ERROR) {
            ALOGE("start() status %d", status);
        } else {
            mActive = true;
            sp<AudioRecordThread> t = mAudioRecordThread;
            if (t != 0) {
                t->resume();
            } else {
                mPreviousPriority = getpriority(PRIO_PROCESS, 0);
                get_sched_policy(0, &mPreviousSchedulingGroup);
                androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
            }
        }
    
        return status;
    }

    在这个函数中主要的工作如下:

        1.重置当前录音Buffer中的录音数据写入的起始位置,录音Buffer的组成在第一篇文章中已经介绍了;

        2.标记mRefreshRemaining为true,从注释中可以看到,他应该是用来强制刷新剩余的frames,后面应该会突出这个变量的作用,先不急;

        3.从mCblk->mFlags的地方获取flags,这里是0x0;

        4.第一次来,肯定走mAudioRecord->start();

        5.如果start失败了,会重新调用restoreRecord_l函数,再次建立输入流通道,这个函数在前一篇文章已经分析过了;

        6.调用AudioRecordThread线程的resume函数;

    这里我们主要分析第4、6步;

    首先分析下AudioRecord.cpp::start()的第4步:mAudioRecord->start()

    mAudioRecord是sp<IAudioRecord>类型的,也就是说他是Binder中的Bp端,我们需要找到BnAudioRecord,可以在AudioFlinger.h中找到Bn端的定义

    frameworksavservicesaudioflingerAudioFlinger.h

        // server side of the client's IAudioRecord
        class RecordHandle : public android::BnAudioRecord {
        public:
            RecordHandle(const sp<RecordThread::RecordTrack>& recordTrack);
            virtual             ~RecordHandle();
            virtual status_t    start(int /*AudioSystem::sync_event_t*/ event, int triggerSession);
            virtual void        stop();
            virtual status_t onTransact(
                uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags);
        private:
            const sp<RecordThread::RecordTrack> mRecordTrack;
    
            // for use from destructor
            void                stop_nonvirtual();
        };

    所以我们继续找RecordHandle类是在哪里实现的,同时,这里可以看到除了start方法以外还有stop方法。

    frameworksavservicesaudioflingerTracks.cpp

    status_t AudioFlinger::RecordHandle::start(int /*AudioSystem::sync_event_t*/ event,
            int triggerSession) {
    
        return mRecordTrack->start((AudioSystem::sync_event_t)event, triggerSession);
    }

    在AudioFlinger.h文件中可以看到const sp<RecordThread::RecordTrack> mRecordTrack;他还是在Tracks.cpp中实现的,继续往下走

    status_t AudioFlinger::RecordThread::RecordTrack::start(AudioSystem::sync_event_t event,
                                                            int triggerSession)
    {
    
        sp<ThreadBase> thread = mThread.promote();
        if (thread != 0) {
            RecordThread *recordThread = (RecordThread *)thread.get();
            return recordThread->start(this, event, triggerSession);
        } else {
            return BAD_VALUE;
        }
    }

    这里的Thread是在AudioRecord.cpp::openRecord_l()中调用createRecordTrack_l的Thread对象,再深入一点,在thread->createRecordTrack_l方法中调用了new RecordTrack(this,...),而RecordTrack是继承TrackBase的,在TrackBase父类的构造函数中TrackBase(ThreadBase *thread,...): RefBase(), mThread(thread),...{},这个父类的实现也是在Tracks.cpp。所以这里的mThread就是RecordThread

    所以这里继续调用RecordThread的start方法

    frameworksavservicesaudioflingerThreads.cpp

    status_t AudioFlinger::RecordThread::start(RecordThread::RecordTrack* recordTrack,
                                               AudioSystem::sync_event_t event,
                                               int triggerSession)
    {
        sp<ThreadBase> strongMe = this;
        status_t status = NO_ERROR;
    
        if (event == AudioSystem::SYNC_EVENT_NONE) {
            recordTrack->clearSyncStartEvent();
        } else if (event != AudioSystem::SYNC_EVENT_SAME) {
            recordTrack->mSyncStartEvent = mAudioFlinger->createSyncEvent(event,
                                           triggerSession,
                                           recordTrack->sessionId(),
                                           syncStartEventCallback,
                                           recordTrack);
            // Sync event can be cancelled by the trigger session if the track is not in a
            // compatible state in which case we start record immediately
            if (recordTrack->mSyncStartEvent->isCancelled()) {
                recordTrack->clearSyncStartEvent();
            } else {
                // do not wait for the event for more than AudioSystem::kSyncRecordStartTimeOutMs
                recordTrack->mFramesToDrop = -
                        ((AudioSystem::kSyncRecordStartTimeOutMs * recordTrack->mSampleRate) / 1000);
            }
        }
    
        {
            // This section is a rendezvous between binder thread executing start() and RecordThread
            AutoMutex lock(mLock);
            if (mActiveTracks.indexOf(recordTrack) >= 0) {
                if (recordTrack->mState == TrackBase::PAUSING) {
                    ALOGV("active record track PAUSING -> ACTIVE");
                    recordTrack->mState = TrackBase::ACTIVE;
                } else {
                    ALOGV("active record track state %d", recordTrack->mState);
                }
                return status;
            }
    
            // TODO consider other ways of handling this, such as changing the state to :STARTING and
            //      adding the track to mActiveTracks after returning from AudioSystem::startInput(),
            //      or using a separate command thread
            recordTrack->mState = TrackBase::STARTING_1;
            mActiveTracks.add(recordTrack);
            mActiveTracksGen++;
            status_t status = NO_ERROR;
            if (recordTrack->isExternalTrack()) {
                mLock.unlock();
                status = AudioSystem::startInput(mId, (audio_session_t)recordTrack->sessionId());
                mLock.lock();
                // FIXME should verify that recordTrack is still in mActiveTracks
                if (status != NO_ERROR) {//0
                    mActiveTracks.remove(recordTrack);
                    mActiveTracksGen++;
                    recordTrack->clearSyncStartEvent();
                    ALOGV("RecordThread::start error %d", status);
                    return status;
                }
            }
            // Catch up with current buffer indices if thread is already running.
            // This is what makes a new client discard all buffered data.  If the track's mRsmpInFront
            // was initialized to some value closer to the thread's mRsmpInFront, then the track could
            // see previously buffered data before it called start(), but with greater risk of overrun.
    
            recordTrack->mRsmpInFront = mRsmpInRear;
            recordTrack->mRsmpInUnrel = 0;
            // FIXME why reset?
            if (recordTrack->mResampler != NULL) {
                recordTrack->mResampler->reset();
            }
            recordTrack->mState = TrackBase::STARTING_2;
            // signal thread to start
            mWaitWorkCV.broadcast();
            if (mActiveTracks.indexOf(recordTrack) < 0) {
                ALOGV("Record failed to start");
                status = BAD_VALUE;
                goto startError;
            }
            return status;
        }
    
    startError:
        if (recordTrack->isExternalTrack()) {
            AudioSystem::stopInput(mId, (audio_session_t)recordTrack->sessionId());
        }
        recordTrack->clearSyncStartEvent();
        // FIXME I wonder why we do not reset the state here?
        return status;
    }

    在这个函数中主要的工作如下:

        1.判断传过来的event的值,从AudioRecord.java可以看到他一直是SYNC_EVENT_NONE,所以这里就清除SyncStartEvent;

        2.判断在mActiveTracks集合中传过来的recordTrack是否是第一个,而我们这是第一次来,肯定会是第一个,而如果不是第一个,也就是说之前因为某种状态已经开始了录音,所以再判断是否是PAUSING状态,更新状态到ACTIVE,然后直接return;

        3.设置recordTrack的状态为STARTING_1,然后加到mActiveTracks集合中,如果此时再去indexOf的话,肯定就是1了;

        4.判断recordTrack是否是外部的Track,而isExternalTrack的定义如下:

                bool        isTimedTrack() const { return (mType == TYPE_TIMED); }
                bool        isOutputTrack() const { return (mType == TYPE_OUTPUT); }
                bool        isPatchTrack() const { return (mType == TYPE_PATCH); }
                bool        isExternalTrack() const { return !isOutputTrack() && !isPatchTrack(); }

    再回忆下,我们在new RecordTrack的时候传入的mType是TrackBase::TYPE_DEFAULT,所以这个recordTrack是外部的Track;

        5.确定是ExternalTrack,那么就会调用AudioSystem::startInput方法开始采集数据,这个sessionId就是上一篇文章中出现的那个了,而对于这个mId,在AudioSystem::startInput中他的类型是audio_io_handle_t,在上一篇文章中,这个io_handle是通过AudioSystem::getInputForAttr获取到的,获取到之后通过checkRecordThread_l(input)获取到了一个RecordThread对象,我们看下RecordThread类:class RecordThread : public ThreadBase,再看下ThreadBase父类,父类的构造函数实现在Threads.cpp文件中,在这里我们发现把input赋值给了mId,也就是说,调用AudioSystem::startInput函数的参数,就是之前建立的输入流input以及生成的sessionId了。

    AudioFlinger::ThreadBase::ThreadBase(const sp<AudioFlinger>& audioFlinger, audio_io_handle_t id,
            audio_devices_t outDevice, audio_devices_t inDevice, type_t type)
        :   Thread(false /*canCallJava*/),
            mType(type),
            mAudioFlinger(audioFlinger),
            // mSampleRate, mFrameCount, mChannelMask, mChannelCount, mFrameSize, mFormat, mBufferSize
            // are set by PlaybackThread::readOutputParameters_l() or
            // RecordThread::readInputParameters_l()
            //FIXME: mStandby should be true here. Is this some kind of hack?
            mStandby(false), mOutDevice(outDevice), mInDevice(inDevice),
            mAudioSource(AUDIO_SOURCE_DEFAULT), mId(id),
            // mName will be set by concrete (non-virtual) subclass
            mDeathRecipient(new PMDeathRecipient(this))
    {
    }

        6.如果mRsmpInRear不为null的话,就重置mRsmpInFront等缓冲区索引;这里显然还没开始录音,所以mRsmpInRear是null的;

        7.设置recordTrack的状态为STARTING_2,然后调用mWaitWorkCV.broadcast()广播通知所有的线程开始工作。注意:这里不得不提前剧透下,在AudioSystem::startInput中,AudioFlinger::RecordThread已经开始跑起来了,所以其实broadcast对RecordThread是没有作用的,并且,需要特别注意的是,这里更新了recordTrack->mState为STARTING_2,之前在加入mActiveTracks时的状态是STARTING_1,这个地方比较有意思,这里先标记下,到时候在分析RecordThread的时候揭晓答案;

        8.判断下recordTrack是否已经加到mActiveTracks集合中了,如果没有的话,就说明start失败了,需要stopInput等;

    接下来继续分析AudioSystem::startInput方法

    frameworksavmedialibmediaAudioSystem.cpp

    status_t AudioSystem::startInput(audio_io_handle_t input,
                                     audio_session_t session)
    {
        const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
        if (aps == 0) return PERMISSION_DENIED;
        return aps->startInput(input, session);
    }

    继续调用AudioPolicyService的startInput方法

    frameworksavservicesaudiopolicyAudioPolicyInterfaceImpl.cpp

    status_t AudioPolicyService::startInput(audio_io_handle_t input,
                                            audio_session_t session)
    {
        if (mAudioPolicyManager == NULL) {
            return NO_INIT;
        }
        Mutex::Autolock _l(mLock);
    
        return mAudioPolicyManager->startInput(input, session);
    }

    继续转发

    frameworksavservicesaudiopolicyAudioPolicyManager.cpp

    status_t AudioPolicyManager::startInput(audio_io_handle_t input,
                                            audio_session_t session)
    {
        ssize_t index = mInputs.indexOfKey(input);
        if (index < 0) {
            ALOGW("startInput() unknown input %d", input);
            return BAD_VALUE;
        }
        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
    
        index = inputDesc->mSessions.indexOf(session);
        if (index < 0) {
            ALOGW("startInput() unknown session %d on input %d", session, input);
            return BAD_VALUE;
        }
    
        // virtual input devices are compatible with other input devices
        if (!isVirtualInputDevice(inputDesc->mDevice)) {
            // for a non-virtual input device, check if there is another (non-virtual) active input
            audio_io_handle_t activeInput = getActiveInput();
            if (activeInput != 0 && activeInput != input) {
                // If the already active input uses AUDIO_SOURCE_HOTWORD then it is closed,
                // otherwise the active input continues and the new input cannot be started.
                sp<AudioInputDescriptor> activeDesc = mInputs.valueFor(activeInput);
                if (activeDesc->mInputSource == AUDIO_SOURCE_HOTWORD) {
                    ALOGW("startInput(%d) preempting low-priority input %d", input, activeInput);
    			
                    stopInput(activeInput, activeDesc->mSessions.itemAt(0));
                    releaseInput(activeInput, activeDesc->mSessions.itemAt(0));
                } else {
                    ALOGE("startInput(%d) failed: other input %d already started", input, activeInput);
                    return INVALID_OPERATION;
                }
            }
        }
    
        if (inputDesc->mRefCount == 0) {
            if (activeInputsCount() == 0) {
                SoundTrigger::setCaptureState(true);
            }
            setInputDevice(input, getNewInputDevice(input), true /* force */);
    
            // automatically enable the remote submix output when input is started if not
            // used by a policy mix of type MIX_TYPE_RECORDERS
            // For remote submix (a virtual device), we open only one input per capture request.
            if (audio_is_remote_submix_device(inputDesc->mDevice)) {
    			ALOGV("audio_is_remote_submix_device(inputDesc->mDevice)");
                String8 address = String8("");
                if (inputDesc->mPolicyMix == NULL) {
                    address = String8("0");
                } else if (inputDesc->mPolicyMix->mMixType == MIX_TYPE_PLAYERS) {
                    address = inputDesc->mPolicyMix->mRegistrationId;
                }
                if (address != "") {
                    setDeviceConnectionStateInt(AUDIO_DEVICE_OUT_REMOTE_SUBMIX,
                            AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
                            address);
                }
            }
        }
    
        ALOGV("AudioPolicyManager::startInput() input source = %d", inputDesc->mInputSource);
    
        inputDesc->mRefCount++;
        return NO_ERROR;
    }

    在这个函数中主要工作如下:

        1.通过input找到mInputs集合中的位置,并获取他的inputDesc;

        2.判断input设备是否是虚拟设备,若不是则再判断是否存在active的设备,我们第一次来,不存在的!

        3.第一次来嘛,所以会调用SoundTrigger::setCaptureState(true),不过这个是和语音识别有关系,这里就不多说了;

        4.继续调用setInputDevice函数,其中getNewInputDevice函数的作用是根据input获取audio_devices_t设备,同样,这个设备在上一篇文章中的AudioPolicyManager::getInputForAttr方法中通过getDeviceAndMixForInputSource获取到的,即AUDIO_DEVICE_IN_BUILTIN_MIC内置MIC设备,同时在该函数最后更新了inputDesc->mDevice;

        5.判断是否是remote_submix设备,然后做相应处理;

        6.inputDesc的mRefCount计数+1;

    继续分析setInputDevice函数

    status_t AudioPolicyManager::setInputDevice(audio_io_handle_t input,
                                                audio_devices_t device,
                                                bool force,
                                                audio_patch_handle_t *patchHandle)
    {
        status_t status = NO_ERROR;
    
        sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
        if ((device != AUDIO_DEVICE_NONE) && ((device != inputDesc->mDevice) || force)) {
            inputDesc->mDevice = device;
    
            DeviceVector deviceList = mAvailableInputDevices.getDevicesFromType(device);
            if (!deviceList.isEmpty()) {
                struct audio_patch patch;
                inputDesc->toAudioPortConfig(&patch.sinks[0]);
                // AUDIO_SOURCE_HOTWORD is for internal use only:
                // handled as AUDIO_SOURCE_VOICE_RECOGNITION by the audio HAL
                if (patch.sinks[0].ext.mix.usecase.source == AUDIO_SOURCE_HOTWORD &&
                        !inputDesc->mIsSoundTrigger) {
                    patch.sinks[0].ext.mix.usecase.source = AUDIO_SOURCE_VOICE_RECOGNITION;
                }
                patch.num_sinks = 1;
                //only one input device for now
                deviceList.itemAt(0)->toAudioPortConfig(&patch.sources[0]);
                patch.num_sources = 1;
                ssize_t index;
                if (patchHandle && *patchHandle != AUDIO_PATCH_HANDLE_NONE) {
                    index = mAudioPatches.indexOfKey(*patchHandle);
                } else {
                    index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
                }
                sp< AudioPatch> patchDesc;
                audio_patch_handle_t afPatchHandle = AUDIO_PATCH_HANDLE_NONE;
                if (index >= 0) {
                    patchDesc = mAudioPatches.valueAt(index);
                    afPatchHandle = patchDesc->mAfPatchHandle;
                }
    
                status_t status = mpClientInterface->createAudioPatch(&patch,
                                                                      &afPatchHandle,
                                                                      0);
                if (status == NO_ERROR) {
                    if (index < 0) {
                        patchDesc = new AudioPatch((audio_patch_handle_t)nextUniqueId(),
                                                   &patch, mUidCached);
                        addAudioPatch(patchDesc->mHandle, patchDesc);
                    } else {
                        patchDesc->mPatch = patch;
                    }
                    patchDesc->mAfPatchHandle = afPatchHandle;
                    patchDesc->mUid = mUidCached;
                    if (patchHandle) {
                        *patchHandle = patchDesc->mHandle;
                    }
                    inputDesc->mPatchHandle = patchDesc->mHandle;
                    nextAudioPortGeneration();
                    mpClientInterface->onAudioPatchListUpdate();
                }
            }
        }
        return status;
    }

    在这个函数中主要的工作如下:

        1.这里已经知道device与inputDesc->mDevice都已经是AUDIO_DEVICE_IN_BUILTIN_MIC,但是force是true;

        2.通过device获取mAvailableInputDevices集合中的所有设备,到此刻,我们还只向该集合中添加一个device;

        3.这里我们分析下struct audio_patch;他定义在systemcoreincludesystemaudio.h,这里对audio_patch中的source与sinks进行赋值,注意一点,他把mId(audio_io_handle_t)赋值给了id,然后在这个audio_patch中保存了InputSource,sample_rate,channel_mask,format,hw_module等等,几乎都存进去了;

    struct audio_patch {
        audio_patch_handle_t id;            /* patch unique ID */
        unsigned int      num_sources;      /* number of sources in following array */
        struct audio_port_config sources[AUDIO_PATCH_PORTS_MAX];
        unsigned int      num_sinks;        /* number of sinks in following array */
        struct audio_port_config sinks[AUDIO_PATCH_PORTS_MAX];
    };
    
    struct audio_port_config {
        audio_port_handle_t      id;           /* port unique ID */
        audio_port_role_t        role;         /* sink or source */
        audio_port_type_t        type;         /* device, mix ... */
        unsigned int             config_mask;  /* e.g AUDIO_PORT_CONFIG_ALL */
        unsigned int             sample_rate;  /* sampling rate in Hz */
        audio_channel_mask_t     channel_mask; /* channel mask if applicable */
        audio_format_t           format;       /* format if applicable */
        struct audio_gain_config gain;         /* gain to apply if applicable */
        union {
            struct audio_port_config_device_ext  device;  /* device specific info */
            struct audio_port_config_mix_ext     mix;     /* mix specific info */
            struct audio_port_config_session_ext session; /* session specific info */
        } ext;
    };
    struct audio_port_config_device_ext {
        audio_module_handle_t hw_module;                /* module the device is attached to */
        audio_devices_t       type;                     /* device type (e.g AUDIO_DEVICE_OUT_SPEAKER) */
        char                  address[AUDIO_DEVICE_MAX_ADDRESS_LEN]; /* device address. "" if N/A */
    };
    struct audio_port_config_mix_ext {
        audio_module_handle_t hw_module;    /* module the stream is attached to */
        audio_io_handle_t handle;           /* I/O handle of the input/output stream */
        union {
            //TODO: change use case for output streams: use strategy and mixer attributes
            audio_stream_type_t stream;
            audio_source_t      source;
        } usecase;
    };

        4.调用mpClientInterface->createAudioPatch创建Audio通路;

        5.更新patchDesc的属性;

        6.如果createAudioPatch的status是NO_ERROR的话,就调用mpClientInterface->onAudioPatchListUpdate更新AudioPatch列表;

    这里我们着重分析第4、6步:

    首先分析下AudioPolicyManager.cpp的AudioPolicyManager::setInputDevice的第4步:创建Audio通路

    frameworksavservicesaudiopolicyAudioPolicyClientImpl.cpp

    status_t AudioPolicyService::AudioPolicyClient::createAudioPatch(const struct audio_patch *patch,
                                                                      audio_patch_handle_t *handle,
                                                                      int delayMs)
    {
        return mAudioPolicyService->clientCreateAudioPatch(patch, handle, delayMs);
    }

    继续向下

    frameworksavservicesaudiopolicyAudioPolicyService.cpp

    status_t AudioPolicyService::clientCreateAudioPatch(const struct audio_patch *patch,
                                                    audio_patch_handle_t *handle,
                                                    int delayMs)
    {
        return mAudioCommandThread->createAudioPatchCommand(patch, handle, delayMs);
    }

    还是在这个文件中

    status_t AudioPolicyService::AudioCommandThread::createAudioPatchCommand(
                                                    const struct audio_patch *patch,
                                                    audio_patch_handle_t *handle,
                                                    int delayMs)
    {
        status_t status = NO_ERROR;
    
        sp<AudioCommand> command = new AudioCommand();
        command->mCommand = CREATE_AUDIO_PATCH;
        CreateAudioPatchData *data = new CreateAudioPatchData();
        data->mPatch = *patch;
        data->mHandle = *handle;
        command->mParam = data;
        command->mWaitStatus = true;
        ALOGV("AudioCommandThread() adding create patch delay %d", delayMs);
        status = sendCommand(command, delayMs);
        if (status == NO_ERROR) {
            *handle = data->mHandle;
        }
        return status;
    }

    后面就是把audio_patch封装下,然后加入到AudioCommands队列中去,所以接下来直接看threadLoop中是怎么处理的

    bool AudioPolicyService::AudioCommandThread::threadLoop()
    {
        nsecs_t waitTime = INT64_MAX;
    
        mLock.lock();
        while (!exitPending())
        {
            sp<AudioPolicyService> svc;
            while (!mAudioCommands.isEmpty() && !exitPending()) {
                nsecs_t curTime = systemTime();
                // commands are sorted by increasing time stamp: execute them from index 0 and up
                if (mAudioCommands[0]->mTime <= curTime) {
                    sp<AudioCommand> command = mAudioCommands[0];
                    mAudioCommands.removeAt(0);
                    mLastCommand = command;
    
                    switch (command->mCommand) {
                    case START_TONE: {
                        mLock.unlock();
                        ToneData *data = (ToneData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing start tone %d on stream %d",
                                data->mType, data->mStream);
                        delete mpToneGenerator;
                        mpToneGenerator = new ToneGenerator(data->mStream, 1.0);
                        mpToneGenerator->startTone(data->mType);
                        mLock.lock();
                        }break;
                    case STOP_TONE: {
                        mLock.unlock();
                        ALOGV("AudioCommandThread() processing stop tone");
                        if (mpToneGenerator != NULL) {
                            mpToneGenerator->stopTone();
                            delete mpToneGenerator;
                            mpToneGenerator = NULL;
                        }
                        mLock.lock();
                        }break;
                    case SET_VOLUME: {
                        VolumeData *data = (VolumeData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing set volume stream %d, 
                                volume %f, output %d", data->mStream, data->mVolume, data->mIO);
                        command->mStatus = AudioSystem::setStreamVolume(data->mStream,
                                                                        data->mVolume,
                                                                        data->mIO);
                        }break;
                    case SET_PARAMETERS: {
                        ParametersData *data = (ParametersData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
                                data->mKeyValuePairs.string(), data->mIO);
                        command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
                        }break;
                    case SET_VOICE_VOLUME: {
                        VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing set voice volume volume %f",
                                data->mVolume);
                        command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
                        }break;
                    case STOP_OUTPUT: {
                        StopOutputData *data = (StopOutputData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing stop output %d",
                                data->mIO);
                        svc = mService.promote();
                        if (svc == 0) {
                            break;
                        }
                        mLock.unlock();
                        svc->doStopOutput(data->mIO, data->mStream, data->mSession);
                        mLock.lock();
                        }break;
                    case RELEASE_OUTPUT: {
                        ReleaseOutputData *data = (ReleaseOutputData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing release output %d",
                                data->mIO);
                        svc = mService.promote();
                        if (svc == 0) {
                            break;
                        }
                        mLock.unlock();
                        svc->doReleaseOutput(data->mIO, data->mStream, data->mSession);
                        mLock.lock();
                        }break;
                    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 {
                            command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
                        }
                        } break;
                    case RELEASE_AUDIO_PATCH: {
                        ReleaseAudioPatchData *data = (ReleaseAudioPatchData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing release audio patch");
                        sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
                        if (af == 0) {
                            command->mStatus = PERMISSION_DENIED;
                        } else {
                            command->mStatus = af->releaseAudioPatch(data->mHandle);
                        }
                        } break;
                    case UPDATE_AUDIOPORT_LIST: {
                        ALOGV("AudioCommandThread() processing update audio port list");
                        svc = mService.promote();
                        if (svc == 0) {
                            break;
                        }
                        mLock.unlock();
                        svc->doOnAudioPortListUpdate();
                        mLock.lock();
                        }break;
                    case UPDATE_AUDIOPATCH_LIST: {
                        ALOGV("AudioCommandThread() processing update audio patch list");
                        svc = mService.promote();
                        if (svc == 0) {
                            break;
                        }
                        mLock.unlock();
                        svc->doOnAudioPatchListUpdate();
                        mLock.lock();
                        }break;
                    case SET_AUDIOPORT_CONFIG: {
                        SetAudioPortConfigData *data = (SetAudioPortConfigData *)command->mParam.get();
                        ALOGV("AudioCommandThread() processing set port config");
                        sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
                        if (af == 0) {
                            command->mStatus = PERMISSION_DENIED;
                        } else {
                            command->mStatus = af->setAudioPortConfig(&data->mConfig);
                        }
                        } break;
                    default:
                        ALOGW("AudioCommandThread() unknown command %d", command->mCommand);
                    }
                    {
                        Mutex::Autolock _l(command->mLock);
                        if (command->mWaitStatus) {
                            command->mWaitStatus = false;
                            command->mCond.signal();
                        }
                    }
                    waitTime = INT64_MAX;
                } else {
                    waitTime = mAudioCommands[0]->mTime - curTime;
                    break;
                }
            }
            // release mLock before releasing strong reference on the service as
            // AudioPolicyService destructor calls AudioCommandThread::exit() which acquires mLock.
            mLock.unlock();
            svc.clear();
            mLock.lock();
            if (!exitPending() && mAudioCommands.isEmpty()) {
                // release delayed commands wake lock
                release_wake_lock(mName.string());
                ALOGV("AudioCommandThread() going to sleep");
                mWaitWorkCV.waitRelative(mLock, waitTime);
                ALOGV("AudioCommandThread() waking up");
            }
        }
        // release delayed commands wake lock before quitting
        if (!mAudioCommands.isEmpty()) {
            release_wake_lock(mName.string());
        }
        mLock.unlock();
        return false;
    }

    这里直接看CREATE_AUDIO_PATCH的分支,他调用了AF端的af->createAudioPatch函数,同样在这个loop中,也有后面的UPDATE_AUDIOPATCH_LIST分支

    frameworksavservicesaudioflingerPatchPanel.cpp

    status_t AudioFlinger::createAudioPatch(const struct audio_patch *patch,
                                       audio_patch_handle_t *handle)
    {
        Mutex::Autolock _l(mLock);
        if (mPatchPanel != 0) {
            return mPatchPanel->createAudioPatch(patch, handle);
        }
        return NO_INIT;
    }

    继续往下走 (唉,老实说我都不想走了,绕来绕去的。。

    status_t AudioFlinger::PatchPanel::createAudioPatch(const struct audio_patch *patch,
                                       audio_patch_handle_t *handle)
    {
        ALOGV("createAudioPatch() num_sources %d num_sinks %d handle %d",
              patch->num_sources, patch->num_sinks, *handle);
        status_t status = NO_ERROR;
        audio_patch_handle_t halHandle = AUDIO_PATCH_HANDLE_NONE;
        sp<AudioFlinger> audioflinger = mAudioFlinger.promote();
        if (audioflinger == 0) {
            return NO_INIT;
        }
    
        if (handle == NULL || patch == NULL) {
            return BAD_VALUE;
        }
        if (patch->num_sources == 0 || patch->num_sources > AUDIO_PATCH_PORTS_MAX ||
                patch->num_sinks == 0 || patch->num_sinks > AUDIO_PATCH_PORTS_MAX) {
            return BAD_VALUE;
        }
        // limit number of sources to 1 for now or 2 sources for special cross hw module case.
        // only the audio policy manager can request a patch creation with 2 sources.
        if (patch->num_sources > 2) {
            return INVALID_OPERATION;
        }
    
        if (*handle != AUDIO_PATCH_HANDLE_NONE) {
            for (size_t index = 0; *handle != 0 && index < mPatches.size(); index++) {
                if (*handle == mPatches[index]->mHandle) {
                    ALOGV("createAudioPatch() removing patch handle %d", *handle);
                    halHandle = mPatches[index]->mHalHandle;
                    Patch *removedPatch = mPatches[index];
                    mPatches.removeAt(index);
                    delete removedPatch;
                    break;
                }
            }
        }
    
        Patch *newPatch = new Patch(patch);
    
        switch (patch->sources[0].type) {
            case AUDIO_PORT_TYPE_DEVICE: {
                audio_module_handle_t srcModule = patch->sources[0].ext.device.hw_module;
                ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
                if (index < 0) {
                    ALOGW("createAudioPatch() bad src hw module %d", srcModule);
                    status = BAD_VALUE;
                    goto exit;
                }
                AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
                for (unsigned int i = 0; i < patch->num_sinks; i++) {
                    // support only one sink if connection to a mix or across HW modules
                    if ((patch->sinks[i].type == AUDIO_PORT_TYPE_MIX ||
                            patch->sinks[i].ext.mix.hw_module != srcModule) &&
                            patch->num_sinks > 1) {
                        status = INVALID_OPERATION;
                        goto exit;
                    }
                    // reject connection to different sink types
                    if (patch->sinks[i].type != patch->sinks[0].type) {
                        ALOGW("createAudioPatch() different sink types in same patch not supported");
                        status = BAD_VALUE;
                        goto exit;
                    }
                    // limit to connections between devices and input streams for HAL before 3.0
                    if (patch->sinks[i].ext.mix.hw_module == srcModule &&
                            (audioHwDevice->version() < AUDIO_DEVICE_API_VERSION_3_0) &&
                            (patch->sinks[i].type != AUDIO_PORT_TYPE_MIX)) {
                        ALOGW("createAudioPatch() invalid sink type %d for device source",
                              patch->sinks[i].type);
                        status = BAD_VALUE;
                        goto exit;
                    }
                }
    
                if (patch->sinks[0].ext.device.hw_module != srcModule) {
                    // limit to device to device connection if not on same hw module
                    if (patch->sinks[0].type != AUDIO_PORT_TYPE_DEVICE) {
                        ALOGW("createAudioPatch() invalid sink type for cross hw module");
                        status = INVALID_OPERATION;
                        goto exit;
                    }
                    // special case num sources == 2 -=> reuse an exiting output mix to connect to the
                    // sink
                    if (patch->num_sources == 2) {
                        if (patch->sources[1].type != AUDIO_PORT_TYPE_MIX ||
                                patch->sinks[0].ext.device.hw_module !=
                                        patch->sources[1].ext.mix.hw_module) {
                            ALOGW("createAudioPatch() invalid source combination");
                            status = INVALID_OPERATION;
                            goto exit;
                        }
    
                        sp<ThreadBase> thread =
                                audioflinger->checkPlaybackThread_l(patch->sources[1].ext.mix.handle);
                        newPatch->mPlaybackThread = (MixerThread *)thread.get();
                        if (thread == 0) {
                            ALOGW("createAudioPatch() cannot get playback thread");
                            status = INVALID_OPERATION;
                            goto exit;
                        }
                    } else {
                        audio_config_t config = AUDIO_CONFIG_INITIALIZER;
                        audio_devices_t device = patch->sinks[0].ext.device.type;
                        String8 address = String8(patch->sinks[0].ext.device.address);
                        audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
                        newPatch->mPlaybackThread = audioflinger->openOutput_l(
                                                                 patch->sinks[0].ext.device.hw_module,
                                                                 &output,
                                                                 &config,
                                                                 device,
                                                                 address,
                                                                 AUDIO_OUTPUT_FLAG_NONE);
                        ALOGV("audioflinger->openOutput_l() returned %p",
                                              newPatch->mPlaybackThread.get());
                        if (newPatch->mPlaybackThread == 0) {
                            status = NO_MEMORY;
                            goto exit;
                        }
                    }
                    uint32_t channelCount = newPatch->mPlaybackThread->channelCount();
                    audio_devices_t device = patch->sources[0].ext.device.type;
                    String8 address = String8(patch->sources[0].ext.device.address);
                    audio_config_t config = AUDIO_CONFIG_INITIALIZER;
                    audio_channel_mask_t inChannelMask = audio_channel_in_mask_from_count(channelCount);
                    config.sample_rate = newPatch->mPlaybackThread->sampleRate();
                    config.channel_mask = inChannelMask;
                    config.format = newPatch->mPlaybackThread->format();
                    audio_io_handle_t input = AUDIO_IO_HANDLE_NONE;
                    newPatch->mRecordThread = audioflinger->openInput_l(srcModule,
                                                                        &input,
                                                                        &config,
                                                                        device,
                                                                        address,
                                                                        AUDIO_SOURCE_MIC,
                                                                        AUDIO_INPUT_FLAG_NONE);
                    ALOGV("audioflinger->openInput_l() returned %p inChannelMask %08x",
                          newPatch->mRecordThread.get(), inChannelMask);
                    if (newPatch->mRecordThread == 0) {
                        status = NO_MEMORY;
                        goto exit;
                    }
                    status = createPatchConnections(newPatch, patch);
                    if (status != NO_ERROR) {
                        goto exit;
                    }
                } else {
                    if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
                        if (patch->sinks[0].type == AUDIO_PORT_TYPE_MIX) {
                            sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
                                                                      patch->sinks[0].ext.mix.handle);
                            if (thread == 0) {
                                ALOGW("createAudioPatch() bad capture I/O handle %d",
                                                                      patch->sinks[0].ext.mix.handle);
                                status = BAD_VALUE;
                                goto exit;
                            }
                            status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
                        } else {
                            audio_hw_device_t *hwDevice = audioHwDevice->hwDevice();
                            status = hwDevice->create_audio_patch(hwDevice,
                                                                   patch->num_sources,
                                                                   patch->sources,
                                                                   patch->num_sinks,
                                                                   patch->sinks,
                                                                   &halHandle);
                        }
                    } else {
                        sp<ThreadBase> thread = audioflinger->checkRecordThread_l(
                                                                        patch->sinks[0].ext.mix.handle);
                        if (thread == 0) {
                            ALOGW("createAudioPatch() bad capture I/O handle %d",
                                                                        patch->sinks[0].ext.mix.handle);
                            status = BAD_VALUE;
                            goto exit;
                        }
                        char *address;
                        if (strcmp(patch->sources[0].ext.device.address, "") != 0) {
                            address = audio_device_address_to_parameter(
                                                                patch->sources[0].ext.device.type,
                                                                patch->sources[0].ext.device.address);
                        } else {
                            address = (char *)calloc(1, 1);
                        }
                        AudioParameter param = AudioParameter(String8(address));
                        free(address);
                        param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING),
                                     (int)patch->sources[0].ext.device.type);
                        param.addInt(String8(AUDIO_PARAMETER_STREAM_INPUT_SOURCE),
                                                         (int)patch->sinks[0].ext.mix.usecase.source);
                        ALOGV("createAudioPatch() AUDIO_PORT_TYPE_DEVICE setParameters %s",
                                                                          param.toString().string());
                        status = thread->setParameters(param.toString());
                    }
                }
            } break;
            case AUDIO_PORT_TYPE_MIX: {
                audio_module_handle_t srcModule =  patch->sources[0].ext.mix.hw_module;
                ssize_t index = audioflinger->mAudioHwDevs.indexOfKey(srcModule);
                if (index < 0) {
                    ALOGW("createAudioPatch() bad src hw module %d", srcModule);
                    status = BAD_VALUE;
                    goto exit;
                }
                // limit to connections between devices and output streams
                for (unsigned int i = 0; i < patch->num_sinks; i++) {
                    if (patch->sinks[i].type != AUDIO_PORT_TYPE_DEVICE) {
                        ALOGW("createAudioPatch() invalid sink type %d for mix source",
                              patch->sinks[i].type);
                        status = BAD_VALUE;
                        goto exit;
                    }
                    // limit to connections between sinks and sources on same HW module
                    if (patch->sinks[i].ext.device.hw_module != srcModule) {
                        status = BAD_VALUE;
                        goto exit;
                    }
                }
                AudioHwDevice *audioHwDevice = audioflinger->mAudioHwDevs.valueAt(index);
                sp<ThreadBase> thread =
                                audioflinger->checkPlaybackThread_l(patch->sources[0].ext.mix.handle);
                if (thread == 0) {
                    ALOGW("createAudioPatch() bad playback I/O handle %d",
                              patch->sources[0].ext.mix.handle);
                    status = BAD_VALUE;
                    goto exit;
                }
                if (audioHwDevice->version() >= AUDIO_DEVICE_API_VERSION_3_0) {
                    status = thread->sendCreateAudioPatchConfigEvent(patch, &halHandle);
                } else {
                    audio_devices_t type = AUDIO_DEVICE_NONE;
                    for (unsigned int i = 0; i < patch->num_sinks; i++) {
                        type |= patch->sinks[i].ext.device.type;
                    }
                    char *address;
                    if (strcmp(patch->sinks[0].ext.device.address, "") != 0) {
                        //FIXME: we only support address on first sink with HAL version < 3.0
                        address = audio_device_address_to_parameter(
                                                                    patch->sinks[0].ext.device.type,
                                                                    patch->sinks[0].ext.device.address);
                    } else {
                        address = (char *)calloc(1, 1);
                    }
                    AudioParameter param = AudioParameter(String8(address));
                    free(address);
                    param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING), (int)type);
                    status = thread->setParameters(param.toString());
                }
    
            } break;
            default:
                status = BAD_VALUE;
                goto exit;
        }
    exit:
        ALOGV("createAudioPatch() status %d", status);
        if (status == NO_ERROR) {
            *handle = audioflinger->nextUniqueId();
            newPatch->mHandle = *handle;
            newPatch->mHalHandle = halHandle;
            mPatches.add(newPatch);
            ALOGV("createAudioPatch() added new patch handle %d halHandle %d", *handle, halHandle);
        } else {
            clearPatchConnections(newPatch);
            delete newPatch;
        }
        return status;
    }

    在这个函数中主要工作如下:

        1.在AudioPolicyManager::setInputDevice()函数中,num_sources与num_sinks都为1;

        2.当halHandle不是AUDIO_PATCH_HANDLE_NONE的时候,就去mPatches集合中找到这个halHandle,然后删除他,而在这里,halHandle就是AUDIO_PATCH_HANDLE_NONE;

        3.这里的source.type为AUDIO_PORT_TYPE_DEVICE,获取patch中的audio_module_handle_t,获取AF端的AudioHwDevice,后面有个for循环判断,根据之前的参数设定,均不会进到if里面;

        4.判断source里的audio_module_handle_t与sink里的是否一致,那肯定一致噻;

        5.再判断hal代码中的version版本,我们看下hardwareawaudio ulipaudio_hw.c的adev->hw_device.common.version = AUDIO_DEVICE_API_VERSION_2_0;

        6.调用AF端的checkRecordThread_l函数,即通过audio_io_handle_t从mRecordThreads中获取到RecordThread线程;

        7.通过address创建一个AudioParameter对象,并把source.type与source放入AudioParameter对象中;

        8.调用thread->setParameters把AudioParameter对象传递过去

    这里我们继续分析下第8步:thread->setParameters

    frameworksavservicesaudioflingerThreads.cpp

    status_t AudioFlinger::ThreadBase::setParameters(const String8& keyValuePairs)
    {
        status_t status;
    
        Mutex::Autolock _l(mLock);
    
        return sendSetParameterConfigEvent_l(keyValuePairs);
    }

    emmm,感觉又要绕上一大圈

    status_t AudioFlinger::ThreadBase::sendSetParameterConfigEvent_l(const String8& keyValuePair)
    {
        sp<ConfigEvent> configEvent = (ConfigEvent *)new SetParameterConfigEvent(keyValuePair);
        return sendConfigEvent_l(configEvent);
    }

    把AudioParameter对象转化为ConfigEvent对象,继续调用

    status_t AudioFlinger::ThreadBase::sendConfigEvent_l(sp<ConfigEvent>& event)
    {
        status_t status = NO_ERROR;
    
        mConfigEvents.add(event);
        mWaitWorkCV.signal();
        mLock.unlock();
        {
            Mutex::Autolock _l(event->mLock);
            while (event->mWaitStatus) {
                if (event->mCond.waitRelative(event->mLock, kConfigEventTimeoutNs) != NO_ERROR) {
                    event->mStatus = TIMED_OUT;
                    event->mWaitStatus = false;
                }
            }
            status = event->mStatus;
        }
        mLock.lock();
        return status;
    }

    把ConfigEvent加入到mConfigEvents中,然后调用mWaitWorkCV.signal()通知RecordThread线程可以start了,在线程中接受到mWaitWorkCV.wait(mLock);时就会回到reacquire_wakelock位置,再继续往下,这时候调用了processConfigEvents_l,他就是用来处理ConfigEvent事件的

    void AudioFlinger::ThreadBase::processConfigEvents_l()
    {
        bool configChanged = false;
    
        while (!mConfigEvents.isEmpty()) {
            ALOGV("processConfigEvents_l() remaining events %d", mConfigEvents.size());
            sp<ConfigEvent> event = mConfigEvents[0];
            mConfigEvents.removeAt(0);
            switch (event->mType) {
            case CFG_EVENT_PRIO: {
                PrioConfigEventData *data = (PrioConfigEventData *)event->mData.get();
                // FIXME Need to understand why this has to be done asynchronously
                int err = requestPriority(data->mPid, data->mTid, data->mPrio,
                        true /*asynchronous*/);
                if (err != 0) {
                    ALOGW("Policy SCHED_FIFO priority %d is unavailable for pid %d tid %d; error %d",
                          data->mPrio, data->mPid, data->mTid, err);
                }
            } break;
            case CFG_EVENT_IO: {
                IoConfigEventData *data = (IoConfigEventData *)event->mData.get();
                audioConfigChanged(data->mEvent, data->mParam);
            } break;
            case CFG_EVENT_SET_PARAMETER: {
                SetParameterConfigEventData *data = (SetParameterConfigEventData *)event->mData.get();
                if (checkForNewParameter_l(data->mKeyValuePairs, event->mStatus)) {
                    configChanged = true;
                }
            } break;
            case CFG_EVENT_CREATE_AUDIO_PATCH: {
                CreateAudioPatchConfigEventData *data =
                                                (CreateAudioPatchConfigEventData *)event->mData.get();
                event->mStatus = createAudioPatch_l(&data->mPatch, &data->mHandle);
            } break;
            case CFG_EVENT_RELEASE_AUDIO_PATCH: {
                ReleaseAudioPatchConfigEventData *data =
                                                (ReleaseAudioPatchConfigEventData *)event->mData.get();
                event->mStatus = releaseAudioPatch_l(data->mHandle);
            } break;
            default:
                ALOG_ASSERT(false, "processConfigEvents_l() unknown event type %d", event->mType);
                break;
            }
            {
                Mutex::Autolock _l(event->mLock);
                if (event->mWaitStatus) {
                    event->mWaitStatus = false;
                    event->mCond.signal();
                }
            }
            ALOGV_IF(mConfigEvents.isEmpty(), "processConfigEvents_l() DONE thread %p", this);
        }
    
        if (configChanged) {
            cacheParameters_l();
        }
    }

    这里果然是一直在等待处理mConfigEvents中的事件,而这个event->mType是CFG_EVENT_SET_PARAMETER,所以继续调用checkForNewParameter_l函数,而他肯定是调用的是RecordThread中的啦,这..绕了真·一大圈。

    bool AudioFlinger::RecordThread::checkForNewParameter_l(const String8& keyValuePair,
                                                            status_t& status)
    {
        bool reconfig = false;
    
        status = NO_ERROR;
    
        audio_format_t reqFormat = mFormat;
        uint32_t samplingRate = mSampleRate;
        audio_channel_mask_t channelMask = audio_channel_in_mask_from_count(mChannelCount);
    
        AudioParameter param = AudioParameter(keyValuePair);
        int value;
    
        if (param.getInt(String8(AudioParameter::keySamplingRate), value) == NO_ERROR) {
            samplingRate = value;
            reconfig = true;
        }
        if (param.getInt(String8(AudioParameter::keyFormat), value) == NO_ERROR) {
            if ((audio_format_t) value != AUDIO_FORMAT_PCM_16_BIT) {
                status = BAD_VALUE;
            } else {
                reqFormat = (audio_format_t) value;
                reconfig = true;
            }
        }
        if (param.getInt(String8(AudioParameter::keyChannels), value) == NO_ERROR) {
            audio_channel_mask_t mask = (audio_channel_mask_t) value;
            if (mask != AUDIO_CHANNEL_IN_MONO && mask != AUDIO_CHANNEL_IN_STEREO) {
                status = BAD_VALUE;
            } else {
                channelMask = mask;
                reconfig = true;
            }
        }
        if (param.getInt(String8(AudioParameter::keyFrameCount), value) == NO_ERROR) {
            // do not accept frame count changes if tracks are open as the track buffer
            // size depends on frame count and correct behavior would not be guaranteed
            // if frame count is changed after track creation
            if (mActiveTracks.size() > 0) {
                status = INVALID_OPERATION;
            } else {
                reconfig = true;
            }
        }
        if (param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) {
            // forward device change to effects that have requested to be
            // aware of attached audio device.
            for (size_t i = 0; i < mEffectChains.size(); i++) {
                mEffectChains[i]->setDevice_l(value);
            }
    
            // store input device and output device but do not forward output device to audio HAL.
            // Note that status is ignored by the caller for output device
            // (see AudioFlinger::setParameters()
            if (audio_is_output_devices(value)) {
                mOutDevice = value;
                status = BAD_VALUE;
            } else {
                mInDevice = value;
                // disable AEC and NS if the device is a BT SCO headset supporting those
                // pre processings
                if (mTracks.size() > 0) {
                    bool suspend = audio_is_bluetooth_sco_device(mInDevice) &&
                                        mAudioFlinger->btNrecIsOff();
                    for (size_t i = 0; i < mTracks.size(); i++) {
                        sp<RecordTrack> track = mTracks[i];
                        setEffectSuspended_l(FX_IID_AEC, suspend, track->sessionId());
                        setEffectSuspended_l(FX_IID_NS, suspend, track->sessionId());
                    }
                }
            }
        }
        if (param.getInt(String8(AudioParameter::keyInputSource), value) == NO_ERROR &&
                mAudioSource != (audio_source_t)value) {
            // forward device change to effects that have requested to be
            // aware of attached audio device.
            for (size_t i = 0; i < mEffectChains.size(); i++) {
                mEffectChains[i]->setAudioSource_l((audio_source_t)value);
            }
            mAudioSource = (audio_source_t)value;
        }
    
        if (status == NO_ERROR) {
            status = mInput->stream->common.set_parameters(&mInput->stream->common,
                    keyValuePair.string());
            if (status == INVALID_OPERATION) {
                inputStandBy();
                status = mInput->stream->common.set_parameters(&mInput->stream->common,
                        keyValuePair.string());
            }
            if (reconfig) {
                if (status == BAD_VALUE &&
                    reqFormat == mInput->stream->common.get_format(&mInput->stream->common) &&
                    reqFormat == AUDIO_FORMAT_PCM_16_BIT &&
                    (mInput->stream->common.get_sample_rate(&mInput->stream->common)
                            <= (2 * samplingRate)) &&
                    audio_channel_count_from_in_mask(
                            mInput->stream->common.get_channels(&mInput->stream->common)) <= FCC_2 &&
                    (channelMask == AUDIO_CHANNEL_IN_MONO ||
                            channelMask == AUDIO_CHANNEL_IN_STEREO)) {
                    status = NO_ERROR;
                }
                if (status == NO_ERROR) {
                    readInputParameters_l();
                    sendIoConfigEvent_l(AudioSystem::INPUT_CONFIG_CHANGED);
                }
            }
        }
    
        return reconfig;
    }

    在这里,获取了到了AudioParameter的值,在前面我们知道,他只放入了Routing与InputSource的值,所以这里把patch->sources[0].ext.device.type的属性放入mInDevice,把patch->sinks[0].ext.mix.usecase.source放入mAudioSource中,最后调用HAL层中的set_parameters函数,把mInDevice与mAudioSource设置过去,显然这个reconfig一直是false,也就是说其他的参数并没有改变。

    hardwareawaudio ulipaudio_hw.c

    static int in_set_parameters(struct audio_stream *stream, const char *kvpairs)
    {
        struct sunxi_stream_in *in = (struct sunxi_stream_in *)stream;
        struct sunxi_audio_device *adev = in->dev;
        struct str_parms *parms;
        char *str;
        char value[128];
        int ret, val = 0;
        bool do_standby = false;
    
        ALOGV("in_set_parameters: %s", kvpairs);
    	
    
        parms = str_parms_create_str(kvpairs);
    
        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_INPUT_SOURCE, value, sizeof(value));
    
        pthread_mutex_lock(&adev->lock);
        pthread_mutex_lock(&in->lock);
        if (ret >= 0) {
            val = atoi(value);
            /* no audio source uses val == 0 */
            if ((in->source != val) && (val != 0)) {
                in->source = val;
                do_standby = true;
            }
        }
    
        ret = str_parms_get_str(parms, AUDIO_PARAMETER_STREAM_ROUTING, value, sizeof(value));
        if (ret >= 0) {
            val = atoi(value) & ~AUDIO_DEVICE_BIT_IN;
            if ((adev->mode != AUDIO_MODE_IN_CALL) && (in->device != val) && (val != 0)) {
                in->device = val;
                do_standby = true;
            } else if((adev->mode == AUDIO_MODE_IN_CALL) && (in->source != val) && (val != 0)) {
                in->device = val;
    
    	            select_device(adev);
    		}
    	}
    
        if (do_standby)
            do_input_standby(in);
        pthread_mutex_unlock(&in->lock);
        pthread_mutex_unlock(&adev->lock);
    
        str_parms_destroy(parms);
        return ret;
    }

    1.获取INPUT_SOURCE属性,更新in->source,即AUDIO_SOURCE_MIC;

    2.在adev_open函数中,定义了adev->mode为AUDIO_MODE_NORMAL且定义adev->in_device为AUDIO_DEVICE_IN_BUILTIN_MIC & ~AUDIO_DEVICE_BIT_IN,所以这里仅更新了输入流的in->device,不需要select device了,这里就是内置MIC,AUDIO_DEVICE_IN_BUILTIN_MIC;

    到这里,Audio输入通路就完成了。

    然后分析下AudioPolicyManager.cpp的AudioPolicyManager::setInputDevice的第6步:

    这个mpClientInterface->createAudioPatch的返回值也比较长,一层一层往里面跟,可知,最后是在audio_hw.c中的in_set_parameters给赋值过去的,而ret是调用str_parms_get_str的结果

    这个函数实现是在systemcorelibcutilsstr_parms.c文件中

    int str_parms_get_str(struct str_parms *str_parms, const char *key, char *val,
                          int len)
    {
        char *value;
    
        value = hashmapGet(str_parms->map, (void *)key);
        if (value)
            return strlcpy(val, value, len);
    
        return -ENOENT;
    }

    这个函数的意思就是从str_parms的hashmap中把key的值提取出来并返回;而AUDIO_PARAMETER_STREAM_ROUTING这个key是在调用thread->setParameters(param.toString())之前把type的值放进去的,即

    param.addInt(String8(AUDIO_PARAMETER_STREAM_ROUTING),(int)patch->sources[0].ext.device.type);所以这里的status不是NO_ERROR,所以不会去更新AudioPatch列表了。

    在前面一点,我们注意到AF端的RecordThread已经开始start了,这个要还记得,但是先放在这里,后面一点再分析。

    然后继续分析AudioRecord.cpp::start()的第6步:AudioRecordThread线程的resume函数

    frameworksavmedialibmediaAudioRecord.cpp

    void AudioRecord::AudioRecordThread::resume()
    {
        AutoMutex _l(mMyLock);
        mIgnoreNextPausedInt = true;
        if (mPaused || mPausedInt) {
            mPaused = false;
            mPausedInt = false;
            mMyCond.signal();
        }
    }

    标记mIgnoreNextPausedInt为true,mPaused与mPausedInt都为false,然后调用mMyCond.signal()通知AudioRecordThread线程

    bool AudioRecord::AudioRecordThread::threadLoop()
    {
        {
            AutoMutex _l(mMyLock);
            if (mPaused) {
                mMyCond.wait(mMyLock);
                // caller will check for exitPending()
                return true;
            }
            if (mIgnoreNextPausedInt) {
                mIgnoreNextPausedInt = false;
                mPausedInt = false;
            }
            if (mPausedInt) {
                if (mPausedNs > 0) {
                    (void) mMyCond.waitRelative(mMyLock, mPausedNs);
                } else {
                    mMyCond.wait(mMyLock);
                }
                mPausedInt = false;
                return true;
            }
        }
        nsecs_t ns =  mReceiver.processAudioBuffer();
        switch (ns) {
        case 0:
            return true;
        case NS_INACTIVE:
            pauseInternal();
            return true;
        case NS_NEVER:
            return false;
        case NS_WHENEVER:
            // FIXME increase poll interval, or make event-driven
            ns = 1000000000LL;
            // fall through
        default:
            LOG_ALWAYS_FATAL_IF(ns < 0, "processAudioBuffer() returned %" PRId64, ns);
            pauseInternal(ns);
            return true;
        }
    }

    在AudioRecordThread线程中,在mMyCond.wait(mMyLock);等待signal()信号,这里我们知道mPaused为false,mIgnoreNextPausedInt也将变为false,mPausedInt也为false,所以在下一次循环中,就会调用processAudioBuffer函数,调用之后返回一个NS_WHENEVER,所以将对这个线程进行延时1000000000LL,也就是1s,然后一直循环下去,直到应用终止录音。

    接下来继续分析下processAudioBuffer函数

    nsecs_t AudioRecord::processAudioBuffer()
    {
        mLock.lock();
        if (mAwaitBoost) {
            mAwaitBoost = false;
            mLock.unlock();
            static const int32_t kMaxTries = 5;
            int32_t tryCounter = kMaxTries;
            uint32_t pollUs = 10000;
            do {
                int policy = sched_getscheduler(0);
                if (policy == SCHED_FIFO || policy == SCHED_RR) {
                    break;
                }
                usleep(pollUs);
                pollUs <<= 1;
            } while (tryCounter-- > 0);
            if (tryCounter < 0) {
                ALOGE("did not receive expected priority boost on time");
            }
            // Run again immediately
            return 0;
        }
    
        // Can only reference mCblk while locked
        int32_t flags = android_atomic_and(~CBLK_OVERRUN, &mCblk->mFlags);
    
        // Check for track invalidation
        if (flags & CBLK_INVALID) {
            (void) restoreRecord_l("processAudioBuffer");
            mLock.unlock();
            // Run again immediately, but with a new IAudioRecord
            return 0;
        }
    
        bool active = mActive;
    
        // Manage overrun callback, must be done under lock to avoid race with releaseBuffer()
        bool newOverrun = false;
        if (flags & CBLK_OVERRUN) {
            if (!mInOverrun) {
                mInOverrun = true;
                newOverrun = true;
            }
        }
    
        // Get current position of server
        size_t position = mProxy->getPosition();
    
        // Manage marker callback
        bool markerReached = false;
        size_t markerPosition = mMarkerPosition;
        // FIXME fails for wraparound, need 64 bits
        if (!mMarkerReached && (markerPosition > 0) && (position >= markerPosition)) {
            mMarkerReached = markerReached = true;
        }
    
        // Determine the number of new position callback(s) that will be needed, while locked
        size_t newPosCount = 0;
        size_t newPosition = mNewPosition;
        uint32_t updatePeriod = mUpdatePeriod;
        // FIXME fails for wraparound, need 64 bits
        if (updatePeriod > 0 && position >= newPosition) {
            newPosCount = ((position - newPosition) / updatePeriod) + 1;
            mNewPosition += updatePeriod * newPosCount;
        }
    
        // Cache other fields that will be needed soon
        uint32_t notificationFrames = mNotificationFramesAct;
        if (mRefreshRemaining) {
            mRefreshRemaining = false;
            mRemainingFrames = notificationFrames;
            mRetryOnPartialBuffer = false;
        }
        size_t misalignment = mProxy->getMisalignment();
        uint32_t sequence = mSequence;
    
        // These fields don't need to be cached, because they are assigned only by set():
        //      mTransfer, mCbf, mUserData, mSampleRate, mFrameSize
    
        mLock.unlock();
    
        // perform callbacks while unlocked
        if (newOverrun) {
            mCbf(EVENT_OVERRUN, mUserData, NULL);
        }
        if (markerReached) {
            mCbf(EVENT_MARKER, mUserData, &markerPosition);
        }
        while (newPosCount > 0) {
            size_t temp = newPosition;
            mCbf(EVENT_NEW_POS, mUserData, &temp);
            newPosition += updatePeriod;
            newPosCount--;
        }
        if (mObservedSequence != sequence) {
            mObservedSequence = sequence;
            mCbf(EVENT_NEW_IAUDIORECORD, mUserData, NULL);
        }
    
        // if inactive, then don't run me again until re-started
        if (!active) {
            return NS_INACTIVE;
        }
    
        // Compute the estimated time until the next timed event (position, markers)
        uint32_t minFrames = ~0;
        if (!markerReached && position < markerPosition) {
            minFrames = markerPosition - position;
        }
        if (updatePeriod > 0 && updatePeriod < minFrames) {
            minFrames = updatePeriod;
        }
    
        // If > 0, poll periodically to recover from a stuck server.  A good value is 2.
        static const uint32_t kPoll = 0;
        if (kPoll > 0 && mTransfer == TRANSFER_CALLBACK && kPoll * notificationFrames < minFrames) {
            minFrames = kPoll * notificationFrames;
        }
    
        // Convert frame units to time units
        nsecs_t ns = NS_WHENEVER;
        if (minFrames != (uint32_t) ~0) {
            // This "fudge factor" avoids soaking CPU, and compensates for late progress by server
            static const nsecs_t kFudgeNs = 10000000LL; // 10 ms
            ns = ((minFrames * 1000000000LL) / mSampleRate) + kFudgeNs;
        }
    
        // If not supplying data by EVENT_MORE_DATA, then we're done
        if (mTransfer != TRANSFER_CALLBACK) {
            return ns;
        }
    
        struct timespec timeout;
        const struct timespec *requested = &ClientProxy::kForever;
        if (ns != NS_WHENEVER) {
            timeout.tv_sec = ns / 1000000000LL;
            timeout.tv_nsec = ns % 1000000000LL;
            ALOGV("timeout %ld.%03d", timeout.tv_sec, (int) timeout.tv_nsec / 1000000);
            requested = &timeout;
        }
    
        while (mRemainingFrames > 0) {
    
            Buffer audioBuffer;
            audioBuffer.frameCount = mRemainingFrames;
            size_t nonContig;
            status_t err = obtainBuffer(&audioBuffer, requested, NULL, &nonContig);
            LOG_ALWAYS_FATAL_IF((err != NO_ERROR) != (audioBuffer.frameCount == 0),
                    "obtainBuffer() err=%d frameCount=%zu", err, audioBuffer.frameCount);
            requested = &ClientProxy::kNonBlocking;
            size_t avail = audioBuffer.frameCount + nonContig;
            ALOGV("obtainBuffer(%u) returned %zu = %zu + %zu err %d",
                    mRemainingFrames, avail, audioBuffer.frameCount, nonContig, err);
            if (err != NO_ERROR) {
                if (err == TIMED_OUT || err == WOULD_BLOCK || err == -EINTR) {
                    break;
                }
                ALOGE("Error %d obtaining an audio buffer, giving up.", err);
                return NS_NEVER;
            }
    
            if (mRetryOnPartialBuffer) {
                mRetryOnPartialBuffer = false;
                if (avail < mRemainingFrames) {
                    int64_t myns = ((mRemainingFrames - avail) *
                            1100000000LL) / mSampleRate;
                    if (ns < 0 || myns < ns) {
                        ns = myns;
                    }
                    return ns;
                }
            }
    
            size_t reqSize = audioBuffer.size;
            mCbf(EVENT_MORE_DATA, mUserData, &audioBuffer);
            size_t readSize = audioBuffer.size;
    
            // Sanity check on returned size
            if (ssize_t(readSize) < 0 || readSize > reqSize) {
                ALOGE("EVENT_MORE_DATA requested %zu bytes but callback returned %zd bytes",
                        reqSize, ssize_t(readSize));
                return NS_NEVER;
            }
    
            if (readSize == 0) {
                // The callback is done consuming buffers
                // Keep this thread going to handle timed events and
                // still try to provide more data in intervals of WAIT_PERIOD_MS
                // but don't just loop and block the CPU, so wait
                return WAIT_PERIOD_MS * 1000000LL;
            }
    
            size_t releasedFrames = readSize / mFrameSize;
            audioBuffer.frameCount = releasedFrames;
            mRemainingFrames -= releasedFrames;
            if (misalignment >= releasedFrames) {
                misalignment -= releasedFrames;
            } else {
                misalignment = 0;
            }
    
            releaseBuffer(&audioBuffer);
    
            // FIXME here is where we would repeat EVENT_MORE_DATA again on same advanced buffer
            // if callback doesn't like to accept the full chunk
            if (readSize < reqSize) {
                continue;
            }
    
            // There could be enough non-contiguous frames available to satisfy the remaining request
            if (mRemainingFrames <= nonContig) {
                continue;
            }
    
    #if 0
            // This heuristic tries to collapse a series of EVENT_MORE_DATA that would total to a
            // sum <= notificationFrames.  It replaces that series by at most two EVENT_MORE_DATA
            // that total to a sum == notificationFrames.
            if (0 < misalignment && misalignment <= mRemainingFrames) {
                mRemainingFrames = misalignment;
                return (mRemainingFrames * 1100000000LL) / mSampleRate;
            }
    #endif
    
        }
        mRemainingFrames = notificationFrames;
        mRetryOnPartialBuffer = true;
    
        // A lot has transpired since ns was calculated, so run again immediately and re-calculate
        return 0;
    }

    在这个函数中的主要工作如下:

        1.对于mAwaitBoost变量,我们查找一下,可以知道只有当音频输入标志mFlags为AUDIO_INPUT_FLAG_FAST才有可能是true,而之前分析,在这里mFlags为AUDIO_INPUT_FLAG_NONE;

        2.通过mCblk->mFlags判断是否缓冲区数据已经overrun,并存储在flags中,然后检查track是否失效;

        {插一句,这个mActive是在AudioRecordThread线程resume之前赋值true的,然后我们回过头来看AudioRecord::set函数的结尾,对一大堆变量进行了初始化,而这些变量大部分在这里使用到了,如mInOverrun为false,mMarkerPosition为0,mMarkerReached为false,mNewPosition为0,mUpdatePeriod为0,mSequence为1,mNotificationFramesAct是在之前通过audioFlinger->openRecord获取到的,这里为1024}

        3.检查缓冲区数据是否已经overrun,如果出现overrun,则标记mInOverrun与newOverrun都为true,后面会通过mCbf发送EVENT_OVERRUN事件给到上一层,这个mCbf其实是JNI中的recorderCallback的回调函数;

        4.判断如果当前位置超过标记的位置了,则标记mMarkerReached与markerReached为true,后面会通过mCbf发送EVENT_MARKER事件给到上一层;

        5.判断是否需要更新mRemainingFrames,以及是否需要发送EVENT_NEW_POS以及EVENT_NEW_IAUDIORECORD事件;

        6.这里的mTransfer在AudioRecord::set函数中已经分析了,为TRANSFER_SYNC,所以最后直接return NS_WHENEVER;

    也就是说,在AudioRecordThread这个线程中,通过对mCblk->mFlags的判断来更新当前缓冲区数据的状态,EVENT_OVERRUN/EVENT_MARKER/EVENT_NEW_POS/EVENT_NEW_IAUDIORECORD等。

    好了,AudioRecordThread已经分析完了,之前我们分析到Thread.cpp中的AudioFlinger::ThreadBase::sendConfigEvent_l函数调用了mWaitWorkCV.signal(),所以我们继续分析下RecordThread线程

    frameworksavservicesaudioflingerThreads.cpp

    bool AudioFlinger::RecordThread::threadLoop()
    {
        nsecs_t lastWarning = 0;
    
        inputStandBy();
    
    reacquire_wakelock:
        sp<RecordTrack> activeTrack;
        int activeTracksGen;
        {
            Mutex::Autolock _l(mLock);
            size_t size = mActiveTracks.size();
            activeTracksGen = mActiveTracksGen;
            if (size > 0) {
                // FIXME an arbitrary choice
                activeTrack = mActiveTracks[0];
                acquireWakeLock_l(activeTrack->uid());
                if (size > 1) {
                    SortedVector<int> tmp;
                    for (size_t i = 0; i < size; i++) {
                        tmp.add(mActiveTracks[i]->uid());
                    }
                    updateWakeLockUids_l(tmp);
                }
            } else {
                acquireWakeLock_l(-1);
            }
        }
    
        // used to request a deferred sleep, to be executed later while mutex is unlocked
        uint32_t sleepUs = 0;
    
        // loop while there is work to do
        for (;;) {
            Vector< sp<EffectChain> > effectChains;
    
            // sleep with mutex unlocked
            if (sleepUs > 0) {
                usleep(sleepUs);
                sleepUs = 0;
            }
    
            // activeTracks accumulates a copy of a subset of mActiveTracks
            Vector< sp<RecordTrack> > activeTracks;
    
            // reference to the (first and only) active fast track
            sp<RecordTrack> fastTrack;
    
            // reference to a fast track which is about to be removed
            sp<RecordTrack> fastTrackToRemove;
    
            { // scope for mLock
                Mutex::Autolock _l(mLock);
    
                processConfigEvents_l();
    
                // check exitPending here because checkForNewParameters_l() and
                // checkForNewParameters_l() can temporarily release mLock
                if (exitPending()) {
                    break;
                }
    
                // if no active track(s), then standby and release wakelock
                size_t size = mActiveTracks.size();
                if (size == 0) {
                    standbyIfNotAlreadyInStandby();
                    // exitPending() can't become true here
                    releaseWakeLock_l();
                    ALOGV("RecordThread: loop stopping");
                    // go to sleep
                    mWaitWorkCV.wait(mLock);
                    ALOGV("RecordThread: loop starting");
                    goto reacquire_wakelock;
                }
    			
                if (mActiveTracksGen != activeTracksGen) {
                    activeTracksGen = mActiveTracksGen;
                    SortedVector<int> tmp;
                    for (size_t i = 0; i < size; i++) {
                        tmp.add(mActiveTracks[i]->uid());
                    }
                    updateWakeLockUids_l(tmp);
                }
    
                bool doBroadcast = false;
                for (size_t i = 0; i < size; ) {
    
                    activeTrack = mActiveTracks[i];
                    if (activeTrack->isTerminated()) {
                        if (activeTrack->isFastTrack()) {
                            ALOG_ASSERT(fastTrackToRemove == 0);
                            fastTrackToRemove = activeTrack;
                        }
                        removeTrack_l(activeTrack);
                        mActiveTracks.remove(activeTrack);
                        mActiveTracksGen++;
                        size--;
                        continue;
                    }
    
                    TrackBase::track_state activeTrackState = activeTrack->mState;
                    switch (activeTrackState) {
    
                    case TrackBase::PAUSING:
                        mActiveTracks.remove(activeTrack);
                        mActiveTracksGen++;
                        doBroadcast = true;
                        size--;
                        continue;
    
                    case TrackBase::STARTING_1:
                        sleepUs = 10000;
                        i++;
                        continue;
    
                    case TrackBase::STARTING_2:
                        doBroadcast = true;
                        mStandby = false;
                        activeTrack->mState = TrackBase::ACTIVE;
                        break;
    
                    case TrackBase::ACTIVE:
                        break;
    
                    case TrackBase::IDLE:
                        i++;
                        continue;
    
                    default:
                        LOG_ALWAYS_FATAL("Unexpected activeTrackState %d", activeTrackState);
                    }
    
                    activeTracks.add(activeTrack);
                    i++;
    
                    if (activeTrack->isFastTrack()) {
                        ALOG_ASSERT(!mFastTrackAvail);
                        ALOG_ASSERT(fastTrack == 0);
                        fastTrack = activeTrack;
                    }
                }
                if (doBroadcast) {
                    mStartStopCond.broadcast();
                }
    
                // sleep if there are no active tracks to process
                if (activeTracks.size() == 0) {
                    if (sleepUs == 0) {
                        sleepUs = kRecordThreadSleepUs;
                    }
                    continue;
                }
                sleepUs = 0;
    
                lockEffectChains_l(effectChains);
            }
    
            // thread mutex is now unlocked, mActiveTracks unknown, activeTracks.size() > 0
    
            size_t size = effectChains.size();
            for (size_t i = 0; i < size; i++) {
                // thread mutex is not locked, but effect chain is locked
                effectChains[i]->process_l();
            }
    
            // Push a new fast capture state if fast capture is not already running, or cblk change
            if (mFastCapture != 0) {
                FastCaptureStateQueue *sq = mFastCapture->sq();
                FastCaptureState *state = sq->begin();
                bool didModify = false;
                FastCaptureStateQueue::block_t block = FastCaptureStateQueue::BLOCK_UNTIL_PUSHED;
                if (state->mCommand != FastCaptureState::READ_WRITE /* FIXME &&
                        (kUseFastMixer != FastMixer_Dynamic || state->mTrackMask > 1)*/) {
                    if (state->mCommand == FastCaptureState::COLD_IDLE) {
                        int32_t old = android_atomic_inc(&mFastCaptureFutex);
                        if (old == -1) {
                            (void) syscall(__NR_futex, &mFastCaptureFutex, FUTEX_WAKE_PRIVATE, 1);
                        }
                    }
                    state->mCommand = FastCaptureState::READ_WRITE;
    #if 0   // FIXME
                    mFastCaptureDumpState.increaseSamplingN(mAudioFlinger->isLowRamDevice() ?
                            FastCaptureDumpState::kSamplingNforLowRamDevice : FastMixerDumpState::kSamplingN);
    #endif
                    didModify = true;
                }
                audio_track_cblk_t *cblkOld = state->mCblk;
                audio_track_cblk_t *cblkNew = fastTrack != 0 ? fastTrack->cblk() : NULL;
                if (cblkNew != cblkOld) {
                    state->mCblk = cblkNew;
                    // block until acked if removing a fast track
                    if (cblkOld != NULL) {
                        block = FastCaptureStateQueue::BLOCK_UNTIL_ACKED;
                    }
                    didModify = true;
                }
                sq->end(didModify);
                if (didModify) {
                    sq->push(block);
    #if 0
                    if (kUseFastCapture == FastCapture_Dynamic) {
                        mNormalSource = mPipeSource;
                    }
    #endif
                }
            }
    
            // now run the fast track destructor with thread mutex unlocked
            fastTrackToRemove.clear();
    
            // Read from HAL to keep up with fastest client if multiple active tracks, not slowest one.
            // Only the client(s) that are too slow will overrun. But if even the fastest client is too
            // slow, then this RecordThread will overrun by not calling HAL read often enough.
            // If destination is non-contiguous, first read past the nominal end of buffer, then
            // copy to the right place.  Permitted because mRsmpInBuffer was over-allocated.
    
            int32_t rear = mRsmpInRear & (mRsmpInFramesP2 - 1);
            ssize_t framesRead;
    
            // If an NBAIO source is present, use it to read the normal capture's data
            if (mPipeSource != 0) {
                size_t framesToRead = mBufferSize / mFrameSize;
                framesRead = mPipeSource->read(&mRsmpInBuffer[rear * mChannelCount],
                        framesToRead, AudioBufferProvider::kInvalidPTS);
                if (framesRead == 0) {
                    // since pipe is non-blocking, simulate blocking input
                    sleepUs = (framesToRead * 1000000LL) / mSampleRate;
                }
            // otherwise use the HAL / AudioStreamIn directly
            } else {
                ssize_t bytesRead = mInput->stream->read(mInput->stream,
                        &mRsmpInBuffer[rear * mChannelCount], mBufferSize);
                if (bytesRead < 0) {
                    framesRead = bytesRead;
                } else {
                    framesRead = bytesRead / mFrameSize;
                }
            }
    
            if (framesRead < 0 || (framesRead == 0 && mPipeSource == 0)) {
                ALOGE("read failed: framesRead=%d", framesRead);
                // Force input into standby so that it tries to recover at next read attempt
                inputStandBy();
                sleepUs = kRecordThreadSleepUs;
            }
            if (framesRead <= 0) {
                goto unlock;
            }
            ALOG_ASSERT(framesRead > 0);
    
            if (mTeeSink != 0) {
                (void) mTeeSink->write(&mRsmpInBuffer[rear * mChannelCount], framesRead);
            }
            // If destination is non-contiguous, we now correct for reading past end of buffer.
            {
                size_t part1 = mRsmpInFramesP2 - rear;
                if ((size_t) framesRead > part1) {
                    memcpy(mRsmpInBuffer, &mRsmpInBuffer[mRsmpInFramesP2 * mChannelCount],
                            (framesRead - part1) * mFrameSize);
                }
            }
            rear = mRsmpInRear += framesRead;
    
            size = activeTracks.size();
            // loop over each active track
            for (size_t i = 0; i < size; i++) {
                activeTrack = activeTracks[i];
    
                // skip fast tracks, as those are handled directly by FastCapture
                if (activeTrack->isFastTrack()) {
                    continue;
                }
    
                enum {
                    OVERRUN_UNKNOWN,
                    OVERRUN_TRUE,
                    OVERRUN_FALSE
                } overrun = OVERRUN_UNKNOWN;
    
                // loop over getNextBuffer to handle circular sink
                for (;;) {
    
                    activeTrack->mSink.frameCount = ~0;
    				
                    status_t status = activeTrack->getNextBuffer(&activeTrack->mSink);
                    size_t framesOut = activeTrack->mSink.frameCount;
                    LOG_ALWAYS_FATAL_IF((status == OK) != (framesOut > 0));
    
                    int32_t front = activeTrack->mRsmpInFront;
                    ssize_t filled = rear - front;
                    size_t framesIn;
    
                    if (filled < 0) {
                        // should not happen, but treat like a massive overrun and re-sync
                        framesIn = 0;
                        activeTrack->mRsmpInFront = rear;
                        overrun = OVERRUN_TRUE;
                    } else if ((size_t) filled <= mRsmpInFrames) {
                        framesIn = (size_t) filled;
                    } else {
                        // client is not keeping up with server, but give it latest data
                        framesIn = mRsmpInFrames;
                        activeTrack->mRsmpInFront = front = rear - framesIn;
                        overrun = OVERRUN_TRUE;
                    }
    
                    if (framesOut == 0 || framesIn == 0) {
                        break;
                    }
    
                    if (activeTrack->mResampler == NULL) {
                        // no resampling
                        if (framesIn > framesOut) {
                            framesIn = framesOut;
                        } else {
                            framesOut = framesIn;
                        }
                        int8_t *dst = activeTrack->mSink.i8;
                        while (framesIn > 0) {
                            front &= mRsmpInFramesP2 - 1;
                            size_t part1 = mRsmpInFramesP2 - front;
                            if (part1 > framesIn) {
                                part1 = framesIn;
                            }
                            int8_t *src = (int8_t *)mRsmpInBuffer + (front * mFrameSize);
                            if (mChannelCount == activeTrack->mChannelCount) {
                                memcpy(dst, src, part1 * mFrameSize);
                            } else if (mChannelCount == 1) {
                                upmix_to_stereo_i16_from_mono_i16((int16_t *)dst, (const int16_t *)src,
                                        part1);
                            } else {
                                downmix_to_mono_i16_from_stereo_i16((int16_t *)dst, (const int16_t *)src,
                                        part1);
                            }
                            dst += part1 * activeTrack->mFrameSize;
                            front += part1;
                            framesIn -= part1;
                        }
                        activeTrack->mRsmpInFront += framesOut;
    
                    } else {
                        // resampling
                        // FIXME framesInNeeded should really be part of resampler API, and should
                        //       depend on the SRC ratio
                        //       to keep mRsmpInBuffer full so resampler always has sufficient input
                        size_t framesInNeeded;
                        // FIXME only re-calculate when it changes, and optimize for common ratios
                        // Do not precompute in/out because floating point is not associative
                        // e.g. a*b/c != a*(b/c).
                        const double in(mSampleRate);
                        const double out(activeTrack->mSampleRate);
                        framesInNeeded = ceil(framesOut * in / out) + 1;
                        ALOGV("need %u frames in to produce %u out given in/out ratio of %.4g",
                                    framesInNeeded, framesOut, in / out);
                        // Although we theoretically have framesIn in circular buffer, some of those are
                        // unreleased frames, and thus must be discounted for purpose of budgeting.
                        size_t unreleased = activeTrack->mRsmpInUnrel;
                        framesIn = framesIn > unreleased ? framesIn - unreleased : 0;
                        if (framesIn < framesInNeeded) {
                            ALOGV("not enough to resample: have %u frames in but need %u in to "
                                    "produce %u out given in/out ratio of %.4g",
                                    framesIn, framesInNeeded, framesOut, in / out);
                            size_t newFramesOut = framesIn > 0 ? floor((framesIn - 1) * out / in) : 0;
                            LOG_ALWAYS_FATAL_IF(newFramesOut >= framesOut);
                            if (newFramesOut == 0) {
                                break;
                            }
                            framesInNeeded = ceil(newFramesOut * in / out) + 1;
                            ALOGV("now need %u frames in to produce %u out given out/in ratio of %.4g",
                                    framesInNeeded, newFramesOut, out / in);
                            LOG_ALWAYS_FATAL_IF(framesIn < framesInNeeded);
                            ALOGV("success 2: have %u frames in and need %u in to produce %u out "
                                  "given in/out ratio of %.4g",
                                  framesIn, framesInNeeded, newFramesOut, in / out);
                            framesOut = newFramesOut;
                        } else {
                            ALOGV("success 1: have %u in and need %u in to produce %u out "
                                "given in/out ratio of %.4g",
                                framesIn, framesInNeeded, framesOut, in / out);
                        }
    
                        // reallocate mRsmpOutBuffer as needed; we will grow but never shrink
                        if (activeTrack->mRsmpOutFrameCount < framesOut) {
                            // FIXME why does each track need it's own mRsmpOutBuffer? can't they share?
                            delete[] activeTrack->mRsmpOutBuffer;
                            // resampler always outputs stereo
                            activeTrack->mRsmpOutBuffer = new int32_t[framesOut * FCC_2];
                            activeTrack->mRsmpOutFrameCount = framesOut;
                        }
    
                        // resampler accumulates, but we only have one source track
                        memset(activeTrack->mRsmpOutBuffer, 0, framesOut * FCC_2 * sizeof(int32_t));
                        activeTrack->mResampler->resample(activeTrack->mRsmpOutBuffer, framesOut,
                                // FIXME how about having activeTrack implement this interface itself?
                                activeTrack->mResamplerBufferProvider
                                /*this*/ /* AudioBufferProvider* */);
                        // ditherAndClamp() works as long as all buffers returned by
                        // activeTrack->getNextBuffer() are 32 bit aligned which should be always true.
                        if (activeTrack->mChannelCount == 1) {
                            // temporarily type pun mRsmpOutBuffer from Q4.27 to int16_t
                            ditherAndClamp(activeTrack->mRsmpOutBuffer, activeTrack->mRsmpOutBuffer,
                                    framesOut);
                            // the resampler always outputs stereo samples:
                            // do post stereo to mono conversion
                            downmix_to_mono_i16_from_stereo_i16(activeTrack->mSink.i16,
                                    (const int16_t *)activeTrack->mRsmpOutBuffer, framesOut);
                        } else {
                            ditherAndClamp((int32_t *)activeTrack->mSink.raw,
                                    activeTrack->mRsmpOutBuffer, framesOut);
                        }
                        // now done with mRsmpOutBuffer
    
                    }
    
                    if (framesOut > 0 && (overrun == OVERRUN_UNKNOWN)) {
                        overrun = OVERRUN_FALSE;
                    }
    
                    if (activeTrack->mFramesToDrop == 0) {
                        if (framesOut > 0) {
                            activeTrack->mSink.frameCount = framesOut;
                            activeTrack->releaseBuffer(&activeTrack->mSink);
                        }
                    } else {
                        // FIXME could do a partial drop of framesOut
                        if (activeTrack->mFramesToDrop > 0) {
                            activeTrack->mFramesToDrop -= framesOut;
                            if (activeTrack->mFramesToDrop <= 0) {
                                activeTrack->clearSyncStartEvent();
                            }
                        } else {
                            activeTrack->mFramesToDrop += framesOut;
                            if (activeTrack->mFramesToDrop >= 0 || activeTrack->mSyncStartEvent == 0 ||
                                    activeTrack->mSyncStartEvent->isCancelled()) {
                                ALOGW("Synced record %s, session %d, trigger session %d",
                                      (activeTrack->mFramesToDrop >= 0) ? "timed out" : "cancelled",
                                      activeTrack->sessionId(),
                                      (activeTrack->mSyncStartEvent != 0) ?
                                              activeTrack->mSyncStartEvent->triggerSession() : 0);
                                activeTrack->clearSyncStartEvent();
                            }
                        }
                    }
    
                    if (framesOut == 0) {
                        break;
                    }
                }
    			ALOGE("pngcui - end for(;;)");
    
                switch (overrun) {
                case OVERRUN_TRUE:
                    // client isn't retrieving buffers fast enough
                    if (!activeTrack->setOverflow()) {
                        nsecs_t now = systemTime();
                        // FIXME should lastWarning per track?
                        if ((now - lastWarning) > kWarningThrottleNs) {
                            ALOGW("RecordThread: buffer overflow");
                            lastWarning = now;
                        }
                    }
                    break;
                case OVERRUN_FALSE:
                    activeTrack->clearOverflow();
                    break;
                case OVERRUN_UNKNOWN:
                    break;
                }
    
            }
    
    unlock:
            // enable changes in effect chain
            unlockEffectChains(effectChains);
            // effectChains doesn't need to be cleared, since it is cleared by destructor at scope end
        }
    
        standbyIfNotAlreadyInStandby();
    
        {
            Mutex::Autolock _l(mLock);
            for (size_t i = 0; i < mTracks.size(); i++) {
                sp<RecordTrack> track = mTracks[i];
                track->invalidate();
            }
            mActiveTracks.clear();
            mActiveTracksGen++;
            mStartStopCond.broadcast();
        }
    
        releaseWakeLock();
    
        ALOGV("RecordThread %p exiting", this);
        return false;
    }

    在这个线程中主要的工作如下:

        这个线程其实早在AudioRecord::set函数中就创建好了的,只是一直阻塞在mWaitWorkCV.wait(mLock);中等待mWaitWorkCV的signal,然后再回到reacquire_wakelock位置;

        1.这里注意下,在线程启动的时候,调用了inputStandBy方法,他最终会调用mInput->stream->common.standby,但是in->standby初始值为1,所以在hal层中并没有做实质上的工作;

        2.调用processConfigEvents_l函数,判断mConfigEvents中是否有事件,若有则向外发送mConfigEvents中的事件;

        3.获取mActiveTracks的个数,回顾一下,在Threads.cpp中调用AudioFlinger::RecordThread::start方法时候,会把创建好的RecordThread加入到mActiveTracks中,所以这里的activeTrack就是之前创建好的RecordThread对象了;

        4.既然知道mActiveTracks中已经不为null了,所以for循环就不会再进入到mWaitWorkCV.wait中等待了,要真正的开始干活了;

        5.从mActiveTracks获取到在RecordThread的start方法中加进去的activeTrack;

        6.还记得之前在RecordThread的start方法的时候留的一个悬念吗,这里就揭晓答案,在add到mActiveTracks的时候,mState为STARTING_1,所以这里肯定是STARTING_1,设置sleepUs为10ms后continue,我们再回到for循环开头,这里usleep了!!!我们之前分析到在RecordThread的start方法跑完了的时候才会更新mState为STARTING_2,所以RecordThread::threadLoop也就是在等待RecordThread的start方法跑完,否则会一直在sleep中;

        7.标记doBroadcast为true,mStandby为false,mState为ACTIVE了;

        8.把activeTrack对象拷贝到activeTracks集合中,然后调用mStartStopCond.broadcast(),这个广播注意下,肯定在后面的代码中有作用;

        9.判断是否有音效控制,如有则对该音效做process_l处理;

        10.获取当前AudioBuffer缓冲区的位置rear,这里mRsmpInFrames是mFrameCount * 7,即1024*7,和mRsmpInFramesP2是roundup(mRsmpInFrames),即1024*8

        11.如果是FastCapture方式的话,则调用PipeSource->read去获取数据,否则直接调用HAL层的接口mInput->stream->read获取数据保存到mRsmpInBuffer中,这里采用后者,每次读取2048个字节的数据;

        12.如果获取失败的话,强制设置HAL层的standby状态为1,然后休眠一会,再重新开启read,具体操作会在hal层中的read函数中体现;

        13.获取AudioBuffer剩下的大小part1,如果剩下的大小不足以存下read出来的数据,则把超出的数据拷贝到AudioBuffer环形缓冲区的头部地方,纠正读取缓冲区末尾的错误;

        14.更新rear与mRsmpInRear,向后推进framesRead个单位,而framesRead是bytesRead / mFrameSize,而mFrameSize是audio_stream_in_frame_size获取到的(AudioFlinger::RecordThread::readInputParameters_l()中);

        15.调用activeTrack->getNextBuffer获取下一个buffer;

        16.判断当前Buffer中已经填充了多少数据:filled,如果已经写满则标记OVERRUN_TRUE,如果framesOut或者framesIn为0(这个framesOut是缓冲区中的available frames,如果缓冲区overrun的话,肯定就是0了),则不继续下面了,直接break;

        17.判断是否需要重采样,这里不需要重采样

              1.不进行重采样了的话,就直接通过memcpy把mRsmpInBuffer数据拷贝到activeTrack->mSink.i8中,也就是通过getNextBuffer获取到的那块buffer;

              2.需要重采样的话,会调用activeTrack->mResampler->resample进行重采样之后,通过ditherAndClamp把数据拷贝到activeTrack->mSink中;

        18.判断下当前overrun的状态,如果出现OVERRUN的情况,则调用setOverflow设置mOverflow为true,此时说明应用端读取数据的速度不够快,但是依旧会提供最新的pcm数据,所以如果出现了音频播放时出现跳音,可以排查下这里。

    这里分析下第11步:mInput->stream->read以及第15步:activeTrack->getNextBuffer

    首先分析下第15步:activeTrack->getNextBuffer,获取下一个buffer,因为我们之前就了解AudioBuffer的管理方式,他有一个环形缓冲区,现在这里就是一直在读取底层的数据,他不会在乎应用层有没有去获取我read出来的数据,所以这里就有一个问题,RecordThread线程read出来的数据是怎么写到缓冲区的呢,和后面的AudioRecord.java中read函数去进行交互的。

    frameworksavservicesaudioflingerTracks.cpp

    status_t AudioFlinger::RecordThread::RecordTrack::getNextBuffer(AudioBufferProvider::Buffer* buffer,
            int64_t pts __unused)
    {
        ServerProxy::Buffer buf;
        buf.mFrameCount = buffer->frameCount;
        status_t status = mServerProxy->obtainBuffer(&buf);
        buffer->frameCount = buf.mFrameCount;
        buffer->raw = buf.mRaw;
        if (buf.mFrameCount == 0) {
            // FIXME also wake futex so that overrun is noticed more quickly
            (void) android_atomic_or(CBLK_OVERRUN, &mCblk->mFlags);
        }
        return status;
    }

    继续调用mServerProxy->obtainBuffer获取buf,这个raw就是指向缓冲区的那块共享内存,如果缓冲区填满了的话,则设置mCblk->mFlags为CBLK_OVERRUN

    frameworksavmedialibmediaAudioTrackShared.cpp

    status_t ServerProxy::obtainBuffer(Buffer* buffer, bool ackFlush)
    {
        LOG_ALWAYS_FATAL_IF(buffer == NULL || buffer->mFrameCount == 0);
        if (mIsShutdown) {
            goto no_init;
        }
        {
        audio_track_cblk_t* cblk = mCblk;
        // compute number of frames available to write (AudioTrack) or read (AudioRecord),
        // or use previous cached value from framesReady(), with added barrier if it omits.
        int32_t front;
        int32_t rear;
        // See notes on barriers at ClientProxy::obtainBuffer()
        if (mIsOut) {
            int32_t flush = cblk->u.mStreaming.mFlush;
            rear = android_atomic_acquire_load(&cblk->u.mStreaming.mRear);
            front = cblk->u.mStreaming.mFront;
            if (flush != mFlush) {
                // effectively obtain then release whatever is in the buffer
                size_t mask = (mFrameCountP2 << 1) - 1;
                int32_t newFront = (front & ~mask) | (flush & mask);
                ssize_t filled = rear - newFront;
                // Rather than shutting down on a corrupt flush, just treat it as a full flush
                if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
                    ALOGE("mFlush %#x -> %#x, front %#x, rear %#x, mask %#x, newFront %#x, filled %d=%#x",
                            mFlush, flush, front, rear, mask, newFront, filled, filled);
                    newFront = rear;
                }
                mFlush = flush;
                android_atomic_release_store(newFront, &cblk->u.mStreaming.mFront);
                // There is no danger from a false positive, so err on the side of caution
                if (true /*front != newFront*/) {
                    int32_t old = android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
                    if (!(old & CBLK_FUTEX_WAKE)) {
                        (void) syscall(__NR_futex, &cblk->mFutex,
                                mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE, 1);
                    }
                }
                front = newFront;
            }
        } else {
            front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
            rear = cblk->u.mStreaming.mRear;
        }
        ssize_t filled = rear - front;
        // pipe should not already be overfull
        if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
            ALOGE("Shared memory control block is corrupt (filled=%zd); shutting down", filled);
            mIsShutdown = true;
        }
        if (mIsShutdown) {
            goto no_init;
        }
        // don't allow filling pipe beyond the nominal size
        size_t availToServer;
        if (mIsOut) {
            availToServer = filled;
            mAvailToClient = mFrameCount - filled;
        } else {
            availToServer = mFrameCount - filled;
            mAvailToClient = filled;
        }
        // 'availToServer' may be non-contiguous, so return only the first contiguous chunk
        size_t part1;
        if (mIsOut) {
            front &= mFrameCountP2 - 1;
            part1 = mFrameCountP2 - front;
        } else {
            rear &= mFrameCountP2 - 1;
            part1 = mFrameCountP2 - rear;
        }
        if (part1 > availToServer) {
            part1 = availToServer;
        }
        size_t ask = buffer->mFrameCount;
        if (part1 > ask) {
            part1 = ask;
        }
        // is assignment redundant in some cases?
        buffer->mFrameCount = part1;
        buffer->mRaw = part1 > 0 ?
                &((char *) mBuffers)[(mIsOut ? front : rear) * mFrameSize] : NULL;
        buffer->mNonContig = availToServer - part1;
        // After flush(), allow releaseBuffer() on a previously obtained buffer;
        // see "Acknowledge any pending flush()" in audioflinger/Tracks.cpp.
        if (!ackFlush) {
            mUnreleased = part1;
        }
        return part1 > 0 ? NO_ERROR : WOULD_BLOCK;
        }
    no_init:
        buffer->mFrameCount = 0;
        buffer->mRaw = NULL;
        buffer->mNonContig = 0;
        mUnreleased = 0;
        return NO_INIT;
    }

    这个函数中主要的工作如下:

        1.获取mCblk,这里需要回忆下,mCblk是在AudioRecord::openRecord_l中更新的,即sp<IMemory> iMem通过audioFlinger->openRecord获取到共享内存,然后mCblk=iMem->pointer(),所以实际是在AudioFlinger::openRecord函数中获取到的iMem = cblk = recordTrack->getCblk();

    frameworksavservicesaudioflingerTrackBase.h

    sp<IMemory> getCblk() const { return mCblkMemory; }
    audio_track_cblk_t* cblk() const { return mCblk; }
    sp<IMemory> getBuffers() const { return mBufferMemory; }

        2.获取mCblk中的front、rear,然后计算出filled;

        3.计算出缓冲区中的available frames,然后保存到mFrameCount中;

        4.计算出下一块buf的地址,保存到mRaw中;

    这里就完成把read出来的数据写入到相应的共享内存,即环形缓冲区中了。

    然后再继续简单分析下第12步:调用HAL层的read函数

    hardwareawaudio ulipaudio_hw.c

    static ssize_t in_read(struct audio_stream_in *stream, void* buffer,
                           size_t bytes)
    {
        int ret = 0;
        struct sunxi_stream_in *in 		= (struct sunxi_stream_in *)stream;
        struct sunxi_audio_device *adev = in->dev;
        size_t frames_rq 				= bytes / audio_stream_frame_size(&stream->common);
    
        if (adev->mode == AUDIO_MODE_IN_CALL) {
            memset(buffer, 0, bytes);
        }
    
        /* acquiring hw device mutex systematically is useful if a low priority thread is waiting
         * on the input stream mutex - e.g. executing select_mode() while holding the hw device
         * mutex
         */
        if (adev->af_capture_flag && adev->PcmManager.BufExist) {
    	    pthread_mutex_lock(&adev->lock);
        	pthread_mutex_lock(&in->lock);
    	    if (in->standby) {
    	    	in->standby = 0;
    	    }
    	    pthread_mutex_unlock(&adev->lock);
    
    	    if (ret < 0)
    	        goto exit;
    	    ret = ReadPcmData(buffer, bytes, &adev->PcmManager);
    
    	    if (ret > 0)
    	        ret = 0;
    
    	    if (ret == 0 && adev->mic_mute)
    	        memset(buffer, 0, bytes);
    
    	    pthread_mutex_unlock(&in->lock);
       		return bytes;
    	}
    
    	pthread_mutex_lock(&adev->lock);
    	pthread_mutex_lock(&in->lock);
    	if (in->standby) {
    		ret = start_input_stream(in);
    		if (ret == 0)
    			in->standby = 0;
    	}
    	pthread_mutex_unlock(&adev->lock);
    
        if (ret < 0)
            goto exit;
    
        if (in->num_preprocessors != 0) {
            ret = read_frames(in, buffer, frames_rq);
    
        } else if (in->resampler != NULL) {
            ret = read_frames(in, buffer, frames_rq);
    
    	} else {
            ret = pcm_read(in->pcm, buffer, bytes);
    	}
    
        if (ret > 0)
            ret = 0;
    
        if (ret == 0 && adev->mic_mute)
            memset(buffer, 0, bytes);
    
    exit:
        if (ret < 0)
            usleep(bytes * 1000000 / audio_stream_frame_size(&stream->common) /
                   in_get_sample_rate(&stream->common));
    
        pthread_mutex_unlock(&in->lock);
        return bytes;
    }

    这里就直接调用到了HAL层中的in_read函数,这个函数一般soc厂家不一样,实现也不一样,这里做简要介绍

        1.如果当前输入流的standby为true的时候,也就是第一次read时,调用start_input_stream函数去打开mic设备节点;

        2.如果stream_in的num_preprocessors或者resampler有数据的时候,则调用read_frames函数获取数据,否则直接调用pcm_read获取。其实他们最终都是调用的pcm_read去获取数据的,这个函数是tinyalsa架构提供的,这个库的实现源码位置:external inyalsa,我们在测试音频的时候一般也是通过这几个程序去测试的;

        3.把读取到的数据喂给buffer,最后休息一下;

    这里再继续分析下start_input_stream函数

    static int start_input_stream(struct sunxi_stream_in *in)
    {
    	int ret = 0;
    	int in_ajust_rate = 0;
    	struct sunxi_audio_device *adev = in->dev;
    
    	adev->active_input = in;
    
    	F_LOG;
    	adev->in_device = in->device;
    	select_device(adev);
    
    	if (in->need_echo_reference && in->echo_reference == NULL)
            	in->echo_reference = get_echo_reference(adev,
                                            AUDIO_FORMAT_PCM_16_BIT,
                                            in->config.channels,
                                            in->requested_rate);
    
    	in_ajust_rate = in->requested_rate;
    	ALOGD(">>>>>> in_ajust_rate is : %d", in_ajust_rate);
    		// out/in stream should be both 44.1K serial
    	switch(CASE_NAME){
    	case 0 :
    	case 1 :
    		in_ajust_rate = SAMPLING_RATE_44K;
    		if((adev->mode == AUDIO_MODE_IN_CALL) && (adev->out_device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO) ){
    			in_ajust_rate = SAMPLING_RATE_8K;
    		}
    		if((adev->mode == AUDIO_MODE_IN_COMMUNICATION) && (adev->out_device == AUDIO_DEVICE_OUT_BLUETOOTH_SCO_HEADSET) ){
    			in_ajust_rate = SAMPLING_RATE_8K;
    		}
    		break;
    	case 2 :
    		if(adev->mode == AUDIO_MODE_IN_CALL)
    			in_ajust_rate = in->requested_rate;
    		else
    			in_ajust_rate = SAMPLING_RATE_44K;
    
    	default :	
    		break;
    
    	}
    	if (adev->mode == AUDIO_MODE_IN_CALL)
    	    in->pcm = pcm_open(0, PORT_VIR_CODEC, PCM_IN, &in->config);
    	else
    	    in->pcm = pcm_open(0, PORT_CODEC, PCM_IN, &in->config);
    
        	if (!pcm_is_ready(in->pcm)) {
                ALOGE("cannot open pcm_in driver: %s", pcm_get_error(in->pcm));
                pcm_close(in->pcm);
                adev->active_input = NULL;
                return -ENOMEM;
        	}
    
    	if (in->requested_rate != in->config.rate) {
    		in->buf_provider.get_next_buffer = get_next_buffer;
    		in->buf_provider.release_buffer = release_buffer;
    
    		ret = create_resampler(in->config.rate,
    							   in->requested_rate,
    							   in->config.channels,
    							   RESAMPLER_QUALITY_DEFAULT,
    							   &in->buf_provider,
    							   &in->resampler);
    		if (ret != 0) {
    			ALOGE("create in resampler failed, %d -> %d", in->config.rate, in->requested_rate);
    			ret = -EINVAL;
    			goto err;
    		}
    
    		ALOGV("create in resampler OK, %d -> %d", in->config.rate, in->requested_rate);
    	}
    	else
    	{
    		ALOGV("do not use in resampler");
    	}
    
        /* if no supported sample rate is available, use the resampler */
        if (in->resampler) {
            in->resampler->reset(in->resampler);
            in->frames_in = 0;
        }
    	PLOGV("audio_hw::read end!!!");
        return 0;
    
    err:
        if (in->resampler) {
            release_resampler(in->resampler);
        }
    
        return -1;
    }

    这个函数的主要工作包括:

        1.调用select_device去选择一个输入设备;

        2.调用pcm_open函数打开输入设备的节点;

    再继续看下select_device函数

    static void select_device(struct sunxi_audio_device *adev)
    {
    	int ret = -1;
    	int output_device_id = 0;
    	int input_device_id = 0;
    	const char *output_route = NULL;
    	const char *input_route = NULL;
    	const char *phone_route = NULL;
    	int earpiece_on=0, headset_on=0, headphone_on=0, bt_on=0, speaker_on=0;
    	int main_mic_on = 0,sub_mic_on = 0;
    	int bton_temp = 0;
    
    	if(!adev->ar)
    		return;
    
    	audio_route_reset(adev->ar);
    
    	audio_route_update_mixer_old_value(adev->ar);
    	
    	if(spk_dul_used)
    		audio_route_apply_path(adev->ar, "media-speaker-off");
    	else
    		audio_route_apply_path(adev->ar, "media-single-speaker-off");
    	
    	if (adev->mode == AUDIO_MODE_IN_CALL){
    		if(CASE_NAME <= 0){
    			ALOGV("%s,PHONE CASE ERR!!!!!!!!!!!!!!!!!!!! line: %d,CASE_NAME:%d", __FUNCTION__, __LINE__,CASE_NAME);
    			//return CASE_NAME;
    		}
    		headset_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET;  // hp4p
    		headphone_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; // hp3p
    		speaker_on = adev->out_device & AUDIO_DEVICE_OUT_SPEAKER;
    		earpiece_on = adev->out_device & AUDIO_DEVICE_OUT_EARPIECE;
    		bt_on = adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO;
    		//audio_route_reset(adev->ar);
    		ALOGV("****LINE:%d,FUNC:%s, headset_on:%d, headphone_on:%d, speaker_on:%d, earpiece_on:%d, bt_on:%d",__LINE__,__FUNCTION__, headphone_on, headphone_on, speaker_on, earpiece_on, bt_on);
    		if (last_call_path_is_bt && !bt_on) {
    			end_bt_call(adev);
    			last_call_path_is_bt = 0;
    		}
    		if ((headset_on || headphone_on) && speaker_on){
    			output_device_id = OUT_DEVICE_SPEAKER_AND_HEADSET;
    		} else if (earpiece_on) {
    			F_LOG;
    			if (NO_EARPIECE)
    				{
    					F_LOG;
    					if(spk_dul_used){
    						output_device_id = OUT_DEVICE_SPEAKER;
    					}else{
    						output_device_id = OUT_DEVICE_SINGLE_SPEAKER;
    					}
    				}
    			else
    				{F_LOG;
    				output_device_id = OUT_DEVICE_EARPIECE;
    				}
    		} else if (headset_on) {
    			output_device_id = OUT_DEVICE_HEADSET;
    		} else if (headphone_on){
    			output_device_id = OUT_DEVICE_HEADPHONES;
    		}else if(bt_on){
    			bton_temp = 1;
    			//bt_start_call(adev);
    			//last_call_path_is_bt = 1;
    			output_device_id = OUT_DEVICE_BT_SCO;
    		}else if(speaker_on){
    			if(spk_dul_used){
    				output_device_id = OUT_DEVICE_SPEAKER;
    			}else{
    				output_device_id = OUT_DEVICE_SINGLE_SPEAKER;
    			}
    		}
    		ALOGV("****** output_id is : %d", output_device_id);
    		phone_route = phone_route_configs[CASE_NAME-1][output_device_id];
    		set_incall_device(adev);
    	}
    	if (adev->active_output) {
    		ALOGV("active_output, ****LINE:%d,FUNC:%s, adev->out_device:%d",__LINE__,__FUNCTION__, adev->out_device);
    		headset_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADSET;  // hp4p
    		headphone_on = adev->out_device & AUDIO_DEVICE_OUT_WIRED_HEADPHONE; // hp3p
    		speaker_on = adev->out_device & AUDIO_DEVICE_OUT_SPEAKER;
    		earpiece_on = adev->out_device & AUDIO_DEVICE_OUT_EARPIECE;
    		bt_on = adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO;
    		//audio_route_reset(adev->ar);
    		ALOGV("****LINE:%d,FUNC:%s, headset_on:%d, headphone_on:%d, speaker_on:%d, earpiece_on:%d, bt_on:%d",__LINE__,__FUNCTION__, headset_on, headphone_on, speaker_on, earpiece_on, bt_on);
    		if ((headset_on || headphone_on) && speaker_on){
    			output_device_id = OUT_DEVICE_SPEAKER_AND_HEADSET;
    		} else if (earpiece_on) {
    			if (NO_EARPIECE){
    				if(spk_dul_used){
    					output_device_id = OUT_DEVICE_SPEAKER;
    				}else{
    					output_device_id = OUT_DEVICE_SINGLE_SPEAKER;
    				}
    			}
    			else
    				output_device_id = OUT_DEVICE_EARPIECE;
    			//output_device_id = OUT_DEVICE_EARPIECE;
    		} else if (headset_on) {
    			output_device_id = OUT_DEVICE_HEADSET;
    		} else if (headphone_on){
    			output_device_id = OUT_DEVICE_HEADSET;
    		}else if(bt_on){
    			output_device_id = OUT_DEVICE_BT_SCO;
    		}else if(speaker_on){
    			if(spk_dul_used){
    				output_device_id = OUT_DEVICE_SPEAKER;
    			}else{
    				output_device_id = OUT_DEVICE_SINGLE_SPEAKER;
    			}
    		}
    		ALOGV("****LINE:%d,FUNC:%s, output_device_id:%d",__LINE__,__FUNCTION__, output_device_id);
    		switch (adev->mode){
    		case AUDIO_MODE_NORMAL:
    			ALOGV("NORMAL mode, ****LINE:%d,FUNC:%s, adev->out_device:%d",__LINE__,__FUNCTION__, adev->out_device);
    			#if 0
    			if(sysopen_music())
    				output_device_id = OUT_DEVICE_HEADSET;
    			else
    				output_device_id = OUT_DEVICE_SPEAKER;
    				//output_device_id = OUT_DEVICE_HEADSET;
    			#endif
    			output_route = normal_route_configs[output_device_id];
    			break;
    		case AUDIO_MODE_RINGTONE:
    			ALOGV("RINGTONE mode, ****LINE:%d,FUNC:%s, adev->out_device:%d",__LINE__,__FUNCTION__, adev->out_device);
    			output_route = ringtone_route_configs[output_device_id];
    			break;
    		case AUDIO_MODE_FM:
    			break;
    		case AUDIO_MODE_MODE_FACTORY_TEST:
    			break;
    		case AUDIO_MODE_IN_CALL:
    			ALOGV("IN_CALL mode, ****LINE:%d,FUNC:%s, adev->out_device:%d",__LINE__,__FUNCTION__, adev->out_device);
    			output_route = phone_keytone_route_configs[CASE_NAME-1][output_device_id];
    			break;
    		case AUDIO_MODE_IN_COMMUNICATION:
    			output_route = normal_route_configs[output_device_id];
    			F_LOG;
    			if (output_device_id == OUT_DEVICE_BT_SCO && !last_communication_is_bt) {
    				F_LOG;
    				/* Open modem PCM channels */
    				if (adev->pcm_modem_dl == NULL) {
    					adev->pcm_modem_dl = pcm_open(0, 4, PCM_OUT, &pcm_config_vx);
    					if (!pcm_is_ready(adev->pcm_modem_dl)) {
    						ALOGE("cannot open PCM modem DL stream: %s", pcm_get_error(adev->pcm_modem_dl));
    						//goto err_open_dl;
    						}
    					}
    				if (adev->pcm_modem_ul == NULL) {
    					adev->pcm_modem_ul = pcm_open(0, 4, PCM_IN, &pcm_config_vx);
    					if (!pcm_is_ready(adev->pcm_modem_ul)) {
    						ALOGE("cannot open PCM modem UL stream: %s", pcm_get_error(adev->pcm_modem_ul));
    						//goto err_open_ul;
    						}
    					}
    				/* Open bt PCM channels */
    				if (adev->pcm_bt_dl == NULL) {
    					adev->pcm_bt_dl = pcm_open(0, PORT_bt, PCM_OUT, &pcm_config_vx);
    					if (!pcm_is_ready(adev->pcm_bt_dl)) {
    						ALOGE("cannot open PCM bt DL stream: %s", pcm_get_error(adev->pcm_bt_dl));
    						//goto err_open_bt_dl;
    						}
    					}
    				if (adev->pcm_bt_ul == NULL) {
    					adev->pcm_bt_ul = pcm_open(0, PORT_bt, PCM_IN, &pcm_config_vx);
    					if (!pcm_is_ready(adev->pcm_bt_ul)) {
    						ALOGE("cannot open PCM bt UL stream: %s", pcm_get_error(adev->pcm_bt_ul));
    						//goto err_open_bt_ul;
    						}
    					}
    				pcm_start(adev->pcm_modem_dl);
    				pcm_start(adev->pcm_modem_ul);
    				pcm_start(adev->pcm_bt_dl);
    				pcm_start(adev->pcm_bt_ul);
    				last_communication_is_bt = true;
    
    			}
    			break;
    		default:
    			break;
    		}
    
    	}
    	if (adev->active_input) {
    		if(adev->out_device & AUDIO_DEVICE_OUT_ALL_SCO){
    			adev->in_device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
    		}
    		int bt_on = adev->in_device & AUDIO_DEVICE_IN_ALL_SCO;
    		ALOGV("record,****LINE:%d,FUNC:%s, adev->in_device:%x,AUDIO_DEVICE_IN_ALL_SCO:%x",__LINE__,__FUNCTION__, adev->in_device,AUDIO_DEVICE_IN_ALL_SCO);
    		if (!bt_on) {
    			if ((adev->mode != AUDIO_MODE_IN_CALL) && (adev->active_input != 0)) {
    			/* sub mic is used for camcorder or VoIP on speaker phone */
    			sub_mic_on = (adev->active_input->source == AUDIO_SOURCE_CAMCORDER) ||
    	                         ((adev->out_device & AUDIO_DEVICE_OUT_SPEAKER) &&
    	                          (adev->active_input->source == AUDIO_SOURCE_VOICE_COMMUNICATION));
    	 		}
    		        if (!sub_mic_on) {
    		            headset_on = adev->in_device & AUDIO_DEVICE_IN_WIRED_HEADSET;
    		            main_mic_on = adev->in_device & AUDIO_DEVICE_IN_BUILTIN_MIC;
    		        }
    		}
    		if (headset_on){
    			input_device_id = IN_SOURCE_HEADSETMIC;
    		} else if (main_mic_on) {
    			input_device_id = IN_SOURCE_MAINMIC;
    		}else if (bt_on && (adev->mode == AUDIO_MODE_IN_COMMUNICATION || adev->mode == AUDIO_MODE_IN_CALL)) {
    			input_device_id = IN_SOURCE_BTMIC;
    		}else{
    			input_device_id = IN_SOURCE_MAINMIC;
    		}
    		ALOGV("fm record,****LINE:%d,FUNC:%s,bt_on:%d,headset_on:%d,main_mic_on;%d,adev->in_device:%x,AUDIO_DEVICE_IN_ALL_SCO:%x",__LINE__,__FUNCTION__,bt_on,headset_on,main_mic_on,adev->in_device,AUDIO_DEVICE_IN_ALL_SCO);
    
    		if (adev->mode == AUDIO_MODE_IN_CALL) {
    			input_route = cap_phone_normal_route_configs[CASE_NAME-1][input_device_id];
    			ALOGV("phone record,****LINE:%d,FUNC:%s, adev->in_device:%x",__LINE__,__FUNCTION__, adev->in_device);
    		} else if (adev->mode == AUDIO_MODE_FM) {
    			//fm_record_enable(true);
    			//fm_record_route(adev->in_device);
    			ALOGV("fm record,****LINE:%d,FUNC:%s",__LINE__,__FUNCTION__);
    		} else if (adev->mode == AUDIO_MODE_NORMAL) {//1
    			if(dmic_used)
    				input_route = dmic_cap_normal_route_configs[input_device_id];
    			else
    				input_route = cap_normal_route_configs[input_device_id];
    			ALOGV("normal record,****LINE:%d,FUNC:%s,adev->in_device:%d",__LINE__,__FUNCTION__,adev->in_device);
    		} else if (adev->mode == AUDIO_MODE_IN_COMMUNICATION) {
    			if(dmic_used)
    				input_route = dmic_cap_normal_route_configs[input_device_id];
    			else
    				input_route = cap_normal_route_configs[input_device_id];
    			F_LOG;
    		}
    
    	}
    	if (phone_route)
    		audio_route_apply_path(adev->ar, phone_route);
    	if (output_route)
            	audio_route_apply_path(adev->ar, output_route);
    	if (input_route)
            	audio_route_apply_path(adev->ar, input_route);
    	audio_route_update_mixer(adev->ar);
    	if (adev->mode == AUDIO_MODE_IN_CALL ){
    		if(bton_temp && last_call_path_is_bt == 0){
    			bt_start_call(adev);
    			last_call_path_is_bt = 1;
    		}
    	}
    }

    所以说,我们如果需要修改输入设备的时候,可以在这个函数中根据相应的参数去更改,同样,对于其他方案来说,也是可以参考这一套方法去实现的。

    具体获取pcm数据的方法介绍到这里,总结下RecordThread线程的作用:这个线程中,就会真正去获取pcm数据,更新缓冲区中的数据,判断当前是否处于overrun的状态等等。

    总结:

        在startRecording函数中,他建立起了录音通道路由route,并且开启了应用层的录音线程,并把录音数据从驱动中读取到AudioBuffer环形缓冲区来。此时录音设备节点已经被open了,并开始read数据了

    由于作者内功有限,若文章中存在错误或不足的地方,还请给位大佬指出,不胜感激!

  • 相关阅读:
    将数字转换千分位分隔形式
    根据字符分割字符串的三种写法
    取出字符串中的汉字、字母或是数字
    生成n位随机字符串
    python中类的继承
    汇编语言与计算机体系结构
    DMA(direct memory access)直接内存访问
    数学归纳法证明时间复杂度
    具体名词的理解、单词的深意
    python的类和对象
  • 原文地址:https://www.cnblogs.com/pngcui/p/10016563.html
Copyright © 2020-2023  润新知