zoukankan      html  css  js  c++  java
  • (六)Audio子系统之AudioRecord.release

     

    在上一篇文章《(五)Audio子系统之AudioRecord.stop》中已经介绍了AudioRecord如何暂停录制,接下来,继续分析AudioRecord方法中的release的实现

     

      函数原型:

        public void release()

           作用:

        释放Audio资源

      参数:

        无

      返回值:

        无

     

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

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

        public void release() {
            try {
                stop();
            } catch(IllegalStateException ise) {
                // don't raise an exception, we're releasing the resources.
            }
            native_release();
            mState = STATE_UNINITIALIZED;
        }

    1.再调用一次stop方法,这里会在AudioRecord::stop()方法中遭遇mActive,导致直接return;

    2.调用native_release的native方法;

    3.更新mState为STATE_UNINITIALIZED;

    这里分析下native_release函数

    static void android_media_AudioRecord_release(JNIEnv *env,  jobject thiz) {
        sp<AudioRecord> lpRecorder = setAudioRecord(env, thiz, 0);
        if (lpRecorder == NULL) {
            return;
        }
        ALOGV("About to delete lpRecorder: %p", lpRecorder.get());
        lpRecorder->stop();
    
        audiorecord_callback_cookie *lpCookie = (audiorecord_callback_cookie *)env->GetLongField(
            thiz, javaAudioRecordFields.nativeCallbackCookie);
    
        // reset the native resources in the Java object so any attempt to access
        // them after a call to release fails.
        env->SetLongField(thiz, javaAudioRecordFields.nativeCallbackCookie, 0);
    
        // delete the callback information
        if (lpCookie) {
            Mutex::Autolock l(sLock);
            ALOGV("deleting lpCookie: %p", lpCookie);
            while (lpCookie->busy) {
                if (lpCookie->cond.waitRelative(sLock,
                                                milliseconds(CALLBACK_COND_WAIT_TIMEOUT_MS)) !=
                                                        NO_ERROR) {
                    break;
                }
            }
            sAudioRecordCallBackCookies.remove(lpCookie);
            env->DeleteGlobalRef(lpCookie->audioRecord_class);
            env->DeleteGlobalRef(lpCookie->audioRecord_ref);
            delete lpCookie;
        }
    }
    这里调用setAudioRecord,和之前的getAudioRecord稍有不同,然后把相关的资源都delete掉
    static sp<AudioRecord> setAudioRecord(JNIEnv* env, jobject thiz, const sp<AudioRecord>& ar)
    {
        Mutex::Autolock l(sLock);
        sp<AudioRecord> old =
                (AudioRecord*)env->GetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj);
        if (ar.get()) {
            ar->incStrong((void*)setAudioRecord);
        }
        if (old != 0) {
            old->decStrong((void*)setAudioRecord);
        }
        env->SetLongField(thiz, javaAudioRecordFields.nativeRecorderInJavaObj, (jlong)ar.get());
        return old;
    }

    所以接下来,很多很多地方将会调用自己的析构函数释放相关资源,比如AudioRecordThread与RecordThread两个线程肯定需要释放掉,还有hal层中还打开了mic的设备节点没有关闭,所以也会关闭,这个是在~RecordHandle中调用了,这里简单介绍下

    frameworksavservicesaudioflingerTracks.cpp

    AudioFlinger::RecordHandle::~RecordHandle() {
        stop_nonvirtual();
        mRecordTrack->destroy();
    }
    void AudioFlinger::RecordThread::RecordTrack::destroy()
    {
        // see comments at AudioFlinger::PlaybackThread::Track::destroy()
        sp<RecordTrack> keep(this);
        {
            if (isExternalTrack()) {
                if (mState == ACTIVE || mState == RESUMING) {
                    AudioSystem::stopInput(mThreadIoHandle, (audio_session_t)mSessionId);
                }
                AudioSystem::releaseInput(mThreadIoHandle, (audio_session_t)mSessionId);
            }
            sp<ThreadBase> thread = mThread.promote();
            if (thread != 0) {
                Mutex::Autolock _l(thread->mLock);
                RecordThread *recordThread = (RecordThread *) thread.get();
                recordThread->destroyTrack_l(this);
            }
        }
    }

    看AudioSystem::releaseInput函数

    frameworksavmedialibmediaAudioSystem.cpp

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

    frameworksavservicesaudiopolicyAudioPolicyInterfaceImpl.cpp

    void AudioPolicyService::releaseInput(audio_io_handle_t input,
                                          audio_session_t session)
    {
        if (mAudioPolicyManager == NULL) {
            return;
        }
        sp<AudioPolicyEffects>audioPolicyEffects;
        {
            Mutex::Autolock _l(mLock);
            mAudioPolicyManager->releaseInput(input, session);
            audioPolicyEffects = mAudioPolicyEffects;
        }
        if (audioPolicyEffects != 0) {
            // release audio processors from the input
            status_t status = audioPolicyEffects->releaseInputEffects(input);
            if(status != NO_ERROR) {
                ALOGW("Failed to release effects on input %d", input);
            }
        }
    }

    mAudioPolicyManager->releaseInput

    frameworksavservicesaudiopolicyAudioPolicyManager.cpp

    void AudioPolicyManager::releaseInput(audio_io_handle_t input,
                                          audio_session_t session)
    {
        ALOGV("releaseInput() %d", input);
        ssize_t index = mInputs.indexOfKey(input);
        if (index < 0) {
            ALOGW("releaseInput() releasing unknown input %d", input);
            return;
        }
        sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
        ALOG_ASSERT(inputDesc != 0);
    
        index = inputDesc->mSessions.indexOf(session);
        if (index < 0) {
            ALOGW("releaseInput() unknown session %d on input %d", session, input);
            return;
        }
        inputDesc->mSessions.remove(session);
        if (inputDesc->mOpenRefCount == 0) {
            ALOGW("releaseInput() invalid open ref count %d", inputDesc->mOpenRefCount);
            return;
        }
        inputDesc->mOpenRefCount--;
        if (inputDesc->mOpenRefCount > 0) {
            ALOGV("releaseInput() exit > 0");
            return;
        }
    
        closeInput(input);
        mpClientInterface->onAudioPortListUpdate();
        ALOGV("releaseInput() exit");
    }

    这里把session从mSessions中移出去了,然后继续调用closeInput函数,最后更新了AudioPortList。

    void AudioPolicyManager::closeInput(audio_io_handle_t input)
    {
        ALOGV("closeInput(%d)", input);
    
        sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
        if (inputDesc == NULL) {
            ALOGW("closeInput() unknown input %d", input);
            return;
        }
    
        nextAudioPortGeneration();
    
        ssize_t index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
        if (index >= 0) {
            sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
            status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
            mAudioPatches.removeItemsAt(index);
            mpClientInterface->onAudioPatchListUpdate();
        }
    
        mpClientInterface->closeInput(input);
        mInputs.removeItem(input);
    }

    frameworksavservicesaudiopolicyAudioPolicyClientImpl.cpp

    status_t AudioPolicyService::AudioPolicyClient::closeInput(audio_io_handle_t input)
    {
        sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
        if (af == 0) {
            return PERMISSION_DENIED;
        }
    
        return af->closeInput(input);
    }

    frameworksavservicesaudioflingerAudioFlinger.cpp

    status_t AudioFlinger::closeInput(audio_io_handle_t input)
    {
        return closeInput_nonvirtual(input);
    }
    
    status_t AudioFlinger::closeInput_nonvirtual(audio_io_handle_t input)
    {
        // keep strong reference on the record thread so that
        // it is not destroyed while exit() is executed
        sp<RecordThread> thread;
        {
            Mutex::Autolock _l(mLock);
            thread = checkRecordThread_l(input);
            if (thread == 0) {
                return BAD_VALUE;
            }
    
            ALOGV("closeInput() %d", input);
    
            // If we still have effect chains, it means that a client still holds a handle
            // on at least one effect. We must either move the chain to an existing thread with the
            // same session ID or put it aside in case a new record thread is opened for a
            // new capture on the same session
            sp<EffectChain> chain;
            {
                Mutex::Autolock _sl(thread->mLock);
                Vector< sp<EffectChain> > effectChains = thread->getEffectChains_l();
                // Note: maximum one chain per record thread
                if (effectChains.size() != 0) {
                    chain = effectChains[0];
                }
            }
            if (chain != 0) {
                // first check if a record thread is already opened with a client on the same session.
                // This should only happen in case of overlap between one thread tear down and the
                // creation of its replacement
                size_t i;
                for (i = 0; i < mRecordThreads.size(); i++) {
                    sp<RecordThread> t = mRecordThreads.valueAt(i);
                    if (t == thread) {
                        continue;
                    }
                    if (t->hasAudioSession(chain->sessionId()) != 0) {
                        Mutex::Autolock _l(t->mLock);
                        ALOGV("closeInput() found thread %d for effect session %d",
                              t->id(), chain->sessionId());
                        t->addEffectChain_l(chain);
                        break;
                    }
                }
                // put the chain aside if we could not find a record thread with the same session id.
                if (i == mRecordThreads.size()) {
                    putOrphanEffectChain_l(chain);
                }
            }
            audioConfigChanged(AudioSystem::INPUT_CLOSED, input, NULL);
            mRecordThreads.removeItem(input);
        }
        // FIXME: calling thread->exit() without mLock held should not be needed anymore now that
        // we have a different lock for notification client
        closeInputFinish(thread);
        return NO_ERROR;
    }
    
    void AudioFlinger::closeInputFinish(sp<RecordThread> thread)
    {
        thread->exit();
        AudioStreamIn *in = thread->clearInput();
        ALOG_ASSERT(in != NULL, "in shouldn't be NULL");
        // from now on thread->mInput is NULL
        in->hwDev()->close_input_stream(in->hwDev(), in->stream);
        delete in;
    }

    最后调用hal层in->hwDev()->close_input_stream关闭设备节点

    hardwareawaudio ulipaudio_hw.c

    static void adev_close_input_stream(struct audio_hw_device *dev,
                                       struct audio_stream_in *stream)
    {
        struct sunxi_stream_in *in 			= (struct sunxi_stream_in *)stream;
        struct sunxi_audio_device *ladev 	= (struct sunxi_audio_device *)dev;
    
        in_standby(&stream->common);
    
        if (in->buffer) {
            free(in->buffer);
    	in->buffer = 0;
        }
        if (in->resampler) {
            release_resampler(in->resampler);
    	in->resampler = 0;
        }
        if (ladev->af_capture_flag) {
    	ladev->af_capture_flag = false;
        }
        if (ladev->PcmManager.BufStart) {
    	ladev->PcmManager.BufExist = false;
    	free(ladev->PcmManager.BufStart);
    	ladev->PcmManager.BufStart = 0;
        }
        free(stream);
    
        normal_record_enable(false);
        fm_record_enable(false);
        phone_record_enable(false);
        ALOGD("adev_close_input_stream set voice record status");
        return;
    }
    static int in_standby(struct audio_stream *stream)
    {
        struct sunxi_stream_in *in = (struct sunxi_stream_in *)stream;
        int status;
    
        pthread_mutex_lock(&in->dev->lock);
        pthread_mutex_lock(&in->lock);
        status = do_input_standby(in);
        pthread_mutex_unlock(&in->lock);
        pthread_mutex_unlock(&in->dev->lock);
        return status;
    }
    static int do_input_standby(struct sunxi_stream_in *in)
    {
        struct sunxi_audio_device *adev = in->dev;
    
        if (!in->standby) {
            pcm_close(in->pcm);
            in->pcm = NULL;
    
            adev->active_input = 0;
    		if (in->resampler){
                release_resampler(in->resampler);
                in->resampler = 0;
            }
            if (adev->mode != AUDIO_MODE_IN_CALL) {
                adev->in_device = AUDIO_DEVICE_NONE;
                select_device(adev);
            }
    
            if (in->echo_reference != NULL) {
                /* stop reading from echo reference */
                in->echo_reference->read(in->echo_reference, NULL);
                put_echo_reference(adev, in->echo_reference);
                in->echo_reference = NULL;
            }
    
            in->standby = 1;
        }
        return 0;
    }

    终于是调用了pcm_close了,完成Audio录音的一整个闭环。

    总结:

        在release函数中,主要就是释放掉Android系统中之前申请到的各种资源,以及销毁AudioRecordThread与RecordThread两个线程,最后关闭mic的设备节点,完成Audio所有软硬件资源的释放。

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

     

     
  • 相关阅读:
    微软的PDC2009开完了,上去淘Video喽,有不少好东西
    [摘要]Pushing the Limits of Windows: Paged and Nonpaged Pool From Mark Russinovich's blog
    [摘要]Pushing the Limits of Windows: Virtual Memory From Mark Russinovich's blog
    如何知道在Windbg中得到Memory type(也叫做caching type)
    用ImgBurn做了一张可以安装所有版本的Win7安装盘
    WF 工作流(5)
    ORACLE 綁定變量
    oracle inside(1)
    WF 工作流(1)
    WF 工作流(2)
  • 原文地址:https://www.cnblogs.com/pngcui/p/10016612.html
Copyright © 2011-2022 走看看