在上一篇文章《(五)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. 常见的C语言内存错误及对策(转)

    http://see.xidian.edu.cn/cpp/html/483.html 一.指针没有指向一块合法的内存 定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存.浅显的例子就 ...

  2. Gym 101201G Maximum Islands (最大独立集)

    题意:给定一个图,L代表陆地,W代表水,C表示不确定,问你最多有多少岛. 析:首先给定的L周围必须是是W,只有这样才是最优的,因为如果是L,那么还得有另外的W来包围,不是最优的,那么剩下的就剩下C了, ...

  3. line-height:150% 和 line-height:1.5

    line-height属性的细节与大多数CSS属性不同,line-height支持属性值设置为无单位的数字.有无单位在子元素继承属性时有微妙的不同. 有单位(包括百分比)与无单位之间的区别有单位时,子 ...

  4. Echarts.js使用

    <!DOCTYPE html><html><head> <meta charset="utf-8"> <title>EC ...

  5. CYUSB3014芯片使用EEPROM无法下载固件说明

    当使用128KB的EEPROM存储CYUSB3014芯片的固件时,需要注意,不同厂家的EEPROM存储器,其A0.A1.A2功能不一样,在设计时电路也不一样.Microchip对应的128KB的EEP ...

  6. 让FIREDAC记录数据库的异常日志

    默认FIREDAC不会记录数据库的异常. 比如典型的,提交的时候,非空字段没有给值. 某些人还以为FIREDAC不能捕获数据库的异常,其实FIREDAC是可以捕获并处理数据库的异常事件的. 方法异常简 ...

  7. Solr相似度算法三:DRFSimilarity框架介绍

    地址:http://terrier.org/docs/v3.5/dfr_description.html The Divergence from Randomness (DFR) paradigm i ...

  8. Kafka与.net core(一)安装

    1.安装JDK 目前官网不能直接下载,在网上找到1.8.0版本安装包下载到本地. 1.1.下载jdk并解压 [root@iz2zei2y693gtrgwlibzlwz java]# ls jdk1.. ...

  9. C#中实现对象的深拷贝

    深度拷贝指的是将一个引用类型(包含该类型里的引用类型)拷贝一份(在内存中完完全全是两个对象,没有任何引用关系).......... 直接上代码: /// <summary> /// 对象的 ...

  10. T-Sql之集合

    1.知识点 先了解一下集合概念,集合运算(UNION(并).EXCEPT(补).INTERSECT(交))是指表之间的垂直操作.区别联接(CROSS,INNER.OUTER)是指表之间的水平操作,基础 ...