在上一篇文章《(五)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中调用了,这里简单介绍下

frameworks\av\services\audioflinger\Tracks.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函数

frameworks\av\media\libmedia\AudioSystem.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);
}

frameworks\av\services\audiopolicy\AudioPolicyInterfaceImpl.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

frameworks\av\services\audiopolicy\AudioPolicyManager.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);
}

frameworks\av\services\audiopolicy\AudioPolicyClientImpl.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);
}

frameworks\av\services\audioflinger\AudioFlinger.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关闭设备节点

hardware\aw\audio\tulip\audio_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所有软硬件资源的释放。

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

 

(六)Audio子系统之AudioRecord.release的更多相关文章

  1. (四)Audio子系统之AudioRecord.read

      在上一篇文章<(三)Audio子系统之AudioRecord.startRecording>中已经介绍了AudioRecord如何开始录制音频,接下来,继续分析AudioRecord方 ...

  2. (五)Audio子系统之AudioRecord.stop

    在上一篇文章<(四)Audio子系统之AudioRecord.read>中已经介绍了AudioRecord如何获取音频数据,接下来,继续分析AudioRecord方法中的stop的实现 函 ...

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

    在上一篇文章<(二)Audio子系统之new AudioRecord()>中已经介绍了Audio系统如何创建AudioRecord对象以及输入流,并创建了RecordThread线程,接下 ...

  4. (一)Audio子系统之AudioRecord.getMinBufferSize

    在文章<基于Allwinner的Audio子系统分析(Android-5.1)>中已经介绍了Audio的系统架构以及应用层调用的流程,接下来,继续分析AudioRecorder方法中的ge ...

  5. (二)Audio子系统之new AudioRecord()

    在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...

  6. (二)Audio子系统之new AudioRecord()(Android4.4)

    在上一篇文章<(一)Audio子系统之AudioRecord.getMinBufferSize>中已经介绍了AudioRecord如何获取最小缓冲区大小,接下来,继续分析AudioReco ...

  7. 基于Allwinner的Audio子系统分析(Android-5.1)

    前言 一直想总结下Audio子系统的博客,但是各种原因(主要还是自己懒>_<),一直拖到现在才开始重新整理,期间看过H8(Android-4.4),T3(Android-4.4),A64( ...

  8. 嵌入式Linux驱动学习之路(十六)输入子系统

    以前写的一些输入设备的驱动都是采用字符设备处理的.问题由此而来,Linux开源社区的大神们看到了这大量输入设备如此分散不堪,有木有可以实现一种机制,可以对分散的.不同类别的输入设备进行统一的驱动,所以 ...

  9. Spring Security(六):2.3 Release Numbering

    It is useful to understand how Spring Security release numbers work, as it will help you identify th ...

随机推荐

  1. Zookeeper 源码(三)Zookeeper 客户端源码

    Zookeeper 源码(三)Zookeeper 客户端源码 Zookeeper 客户端主要有以下几个重要的组件.客户端会话创建可以分为三个阶段:一是初始化阶段.二是会话创建阶段.三是响应处理阶段. ...

  2. Java 设计模式系列(二三)访问者模式(Vistor)

    Java 设计模式系列(二三)访问者模式(Vistor) 访问者模式是对象的行为模式.访问者模式的目的是封装一些施加于某种数据结构元素之上的操作.一旦这些操作需要修改的话,接受这个操作的数据结构则可以 ...

  3. 从iOS 11看怎样设计APP图标

    苹果WWDC2017开发者大会已经尘埃落定,除了新产品的发布,iOS 11也正式亮相.新系统中,地图.App Store.时钟.相机.联系人等等原生应用都换了新的图标.此次图标的变化势必也会激发下一个 ...

  4. 11 Mortal Fibonacci Rabbits

    Problem Figure 4. A figure illustrating the propagation of Fibonacci's rabbits if they die after thr ...

  5. BI失败的原因

    最最重要的, 要有个清晰的目标和范围. 有些客户, 完全脑袋一热开始上BI, 连根本上要BI来解决什么问题都不知道.作为企业的CIO, 首先要知道上BI项目是不是符合企业的战略目标, 是不是能给企业带 ...

  6. 用JQ去实现一个轮播效果

    前提:用JQ去实现轮播效果一步步的做一个梳理. 首先肯定是轮播的HTML和CSS样式了: <body> <div class="pic"> <div ...

  7. MySQL性能调优与架构设计——第9章 MySQL数据库Schema设计的性能优化

    第9章 MySQL数据库Schema设计的性能优化 前言: 很多人都认为性能是在通过编写代码(程序代码或者是数据库代码)的过程中优化出来的,其实这是一个非常大的误区.真正影响性能最大的部分是在设计中就 ...

  8. ZOJ3775 ?(>_o)! 2017-04-13 23:37 110人阅读 评论(0) 收藏

    ?(>_o)! Time Limit: 2 Seconds      Memory Limit: 65536 KB ?(>_o)! is a pseudo-object-oriented ...

  9. 咏南中间件增加HTTPS.SYS支持

    咏南中间件增加HTTPS.SYS支持 老客户可免费升级. HTTPS.SYS可以开发强大而稳定的REST SERVER. 微软在Windows Vista (server 2008) 以后使用http ...

  10. KVM虚拟机windows系统增加硬盘

    原文:http://www.ilanni.com/?p=6211 前一篇文章介绍了有关linux系统添加硬盘的方法,这次我们来介绍有关windows系统添加的相关步骤. 其实linux和windows ...