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

  函数原型:

public void stop() throws IllegalStateException

作用:

    暂停录制

  参数:

    无

  返回值:

    无

  异常:

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

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

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

    public void stop()
throws IllegalStateException {
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("stop() called on an uninitialized AudioRecord.");
} // stop recording
synchronized(mRecordingStateLock) {
handleFullVolumeRec(false);
native_stop();
mRecordingState = RECORDSTATE_STOPPED;
}
}

首先判断是否已经初始化完毕了,在new AudioRecord()中,mState已经是STATE_INITIALIZED状态了。所以继续分析native_stop函数,最后标记mState已经是RECORDSTATE_STOPPED

frameworks/base/core/jni/android_media_AudioRecord.cpp

static void
android_media_AudioRecord_stop(JNIEnv *env, jobject thiz)
{
sp<AudioRecord> lpRecorder = getAudioRecord(env, thiz);
if (lpRecorder == NULL ) {
jniThrowException(env, "java/lang/IllegalStateException", NULL);
return;
} lpRecorder->stop();
}

继续调用AudioRecord的stop方法

frameworks\av\media\libmedia\AudioRecord.cpp

void AudioRecord::stop()
{
AutoMutex lock(mLock);
if (!mActive) {
return;
}
mActive = false;
mProxy->interrupt();
mAudioRecord->stop();
// the record head position will reset to 0, so if a marker is set, we need
// to activate it again
mMarkerReached = false;
sp<AudioRecordThread> t = mAudioRecordThread;
if (t != 0) {
t->pause();
} else {
setpriority(PRIO_PROCESS, 0, mPreviousPriority);
set_sched_policy(0, mPreviousSchedulingGroup);
}
}

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

1.更新mActive为false;

2.调用mProxy->interrupt,设置cblk->mFlags标记CBLK_INTERRUPT,这个标记是在应用获取共享内存中数据的时候进行判断,是否缓冲区处于INTERRUPT状态;

frameworks\av\media\libmedia\AudioTrackShared.cpp

void ClientProxy::interrupt()
{
audio_track_cblk_t* cblk = mCblk;
if (!(android_atomic_or(CBLK_INTERRUPT, &cblk->mFlags) & CBLK_INTERRUPT)) {
android_atomic_or(CBLK_FUTEX_WAKE, &cblk->mFutex);
(void) syscall(__NR_futex, &cblk->mFutex, mClientInServer ? FUTEX_WAKE_PRIVATE : FUTEX_WAKE,
1);
}
}

3.调用mAudioRecord->stop()方法;

4.标记mMarkerReached为false,这个变量在AudioRecordThread线程中用到了,他会回调,发送EVENT_MARKER事件给应用;

5.调用AudioRecordThread线程中的pause方法,暂停AudioRecordThread线程;

void AudioRecord::AudioRecordThread::pause()
{
AutoMutex _l(mMyLock);
mPaused = true;
}

我们知道,还有一个重要的线程:RecordThread,这个线程怎么停止呢,所以继续分析mAudioRecord->stop(),这个mAudioRecord是IAudioRecord对象,之前在分析mAudioRecord->start()的时候已经知道,IAudioRecord类是在RecordHandle类中实现的

frameworks\av\services\audioflinger\Tracks.cpp

void AudioFlinger::RecordHandle::stop() {
stop_nonvirtual();
} void AudioFlinger::RecordHandle::stop_nonvirtual() {
ALOGV("RecordHandle::stop()");
mRecordTrack->stop();
}

继续调用mRecordTrack->stop()函数

void AudioFlinger::RecordThread::RecordTrack::stop()
{
sp<ThreadBase> thread = mThread.promote();
if (thread != 0) {
RecordThread *recordThread = (RecordThread *)thread.get();
if (recordThread->stop(this) && isExternalTrack()) {
AudioSystem::stopInput(mThreadIoHandle, (audio_session_t)mSessionId);
}
}
}

这里做了两件事:

1.获取RecordThread线程,然后调用stop方法;

2.之前在startRecording分析中已经知道这个recordTrack是外部的Track;

3.调用AudioSystem::stopInput();

首先看下RecordTrack::stop()的第1步:RecordThread线程的stop方法

frameworks\av\services\audioflinger\Threads.cpp

bool AudioFlinger::RecordThread::stop(RecordThread::RecordTrack* recordTrack) {
ALOGV("RecordThread::stop");
AutoMutex _l(mLock);
if (mActiveTracks.indexOf(recordTrack) != 0 || recordTrack->mState == TrackBase::PAUSING) {
return false;
}
// note that threadLoop may still be processing the track at this point [without lock]
recordTrack->mState = TrackBase::PAUSING;
// do not wait for mStartStopCond if exiting
if (exitPending()) {
return true;
}
// FIXME incorrect usage of wait: no explicit predicate or loop
mStartStopCond.wait(mLock);
// if we have been restarted, recordTrack is in mActiveTracks here
if (exitPending() || mActiveTracks.indexOf(recordTrack) != 0) {
ALOGV("Record stopped OK");
return true;
}
return false;
}

1.标记recordTrack->mState为TrackBase::PAUSING,这个我们在RecordThread::threadLoop中发现,当recordTrack->mState为PAUSING的时候,会把activeTrack从mActiveTracks中remove掉,所以这个线程就又会进入到mWaitWorkCV.wait(mLock);状态中,开启又一轮的睡眠。

2.我们之前在分析RecordThread::threadLoop的第8步的时候提到,当时调用了mStartStopCond.broadcast(),意思就是告诉这里的stop函数,你发的TrackBase::PAUSING我已经收到了;

3.最后判断下activeTrack是否真的从mActiveTracks中remove掉了,如果是,那么表示stop成功了。

好了,这里就把RecordThread线程也停止了,但是注意:AudioRecordThread与RecordThread两个线程都是处于阻塞状态,并没有销毁。

接下来分析RecordTrack::stop()的第3步:AudioSystem::stopInput();

frameworks\av\media\libmedia\AudioSystem.cpp

status_t AudioSystem::stopInput(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->stopInput(input, session);
}

继续调用AudioPolicyService的stopInput方法

frameworks\av\services\audiopolicy\AudioPolicyInterfaceImpl.cpp

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

转发

status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
audio_session_t session)
{
ALOGV("stopInput() input %d", input);
ssize_t index = mInputs.indexOfKey(input);
if (index < 0) {
ALOGW("stopInput() unknown input %d", input);
return BAD_VALUE;
}
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index); index = inputDesc->mSessions.indexOf(session);
if (index < 0) {
ALOGW("stopInput() unknown session %d on input %d", session, input);
return BAD_VALUE;
} if (inputDesc->mRefCount == 0) {
ALOGW("stopInput() input %d already stopped", input);
return INVALID_OPERATION;
} inputDesc->mRefCount--;
if (inputDesc->mRefCount == 0) { // automatically disable the remote submix output when input is stopped if not
// used by a policy mix of type MIX_TYPE_RECORDERS
if (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_UNAVAILABLE,
address);
}
} resetInputDevice(input); if (activeInputsCount() == 0) {
SoundTrigger::setCaptureState(false);
}
}
return NO_ERROR;
}

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

1.从mInputs中获取input索引index以及inputDesc;

2.对inputDesc->mRefCount引用计数进行-1操作;

3.调用resetInputDevice函数重置input;

继续分析下resetInputDevice函数

status_t AudioPolicyManager::resetInputDevice(audio_io_handle_t input,
audio_patch_handle_t *patchHandle)
{
sp<AudioInputDescriptor> inputDesc = mInputs.valueFor(input);
ssize_t index;
if (patchHandle) {
index = mAudioPatches.indexOfKey(*patchHandle);
} else {
index = mAudioPatches.indexOfKey(inputDesc->mPatchHandle);
}
if (index < 0) {
return INVALID_OPERATION;
}
sp< AudioPatch> patchDesc = mAudioPatches.valueAt(index);
status_t status = mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
ALOGV("resetInputDevice() releaseAudioPatch returned %d", status);
inputDesc->mPatchHandle = 0;
removeAudioPatch(patchDesc->mHandle);
nextAudioPortGeneration();
mpClientInterface->onAudioPatchListUpdate();
return status;
}

这个函数的主要作用就是更新AudioPatch

所以AudioSystem::stopInput()函数中主要作用就是把mInputs中的inputDesc引用减去,然后重置AudioPatch

总结:

在stop函数中,主要工作就是把AudioRecordThread与RecordThread两个线程挂起来了,同时把startRecording方法中好不容易建立起来的input流也干掉了,所以如果需要继续录音,那么就需要重新调用startRecording方法了。

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

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

  1. (六)Audio子系统之AudioRecord.release

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

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

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

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

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

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

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

  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. Android 4.4KitKat AudioRecord 流程分析

    Android是架构分为三层: 底层      Linux Kernel 中间层  主要由C++实现 (Android 60%源码都是C++实现) 应用层  主要由JAVA开发的应用程序 应用程序执行 ...

  9. [深入理解Android卷一全文-第七章]深入理解Audio系统

    由于<深入理解Android 卷一>和<深入理解Android卷二>不再出版,而知识的传播不应该由于纸质媒介的问题而中断,所以我将在CSDN博客中全文转发这两本书的全部内容. ...

随机推荐

  1. HBase 强制删除表

    业务系统中有一张表drop不掉了. 可以disable,就是drop不掉. 解决办法: 1.将HDFS上的数据删除或移动 hadoop fs -mv /hbase/<table_name> ...

  2. mysql 开通远程连接

    使用localhost好用,但是改成ip地址后不好用,执行sql语句做如下修改: update user set host = '%' where user = 'root'; flush privi ...

  3. POJ2349 Arctic Network 2017-04-13 20:44 40人阅读 评论(0) 收藏

    Arctic Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 19113   Accepted: 6023 D ...

  4. HRBUST1313 火影忍者之~静音 2017-03-06 16:11 39人阅读 评论(0) 收藏

    火影忍者之-静音 传说中的火之国一年一度的公务员选拔又开始了!木叶忍者村此次也要从中选拔出5人来,作为即将上任的新火影纲手的小弟-,可是报考公务员的人数实在是太--多啦!所以纲手的贴身随从-静音小姐, ...

  5. VS中的Debug 和 Release 编译方式的本质区别

    VS中的Debug 和 Release 编译方式的本质区别 Debug 通常称为调试版本,它包含调试信息,并且不作任何优化,便于程序员调试程序.Release 称为发布版本,它往往是进行了各种优化,使 ...

  6. windows下C++操作MySQL数据库

    .安装MySQL 2.建立C++控制台程序,新建CPP源文件,如:sqlconn.cpp 3.工程项目中属性—C/C++--常规—附加包含目录中添加mysql安装目录中的MySQL\MySQL\MyS ...

  7. 数据恢复软Extundelete

    1>概述  作为一名运维人员,保证数据的安全是根本职责,所以在维护系统的时候,要慎重和细心,但是有时也难免发生出现数据被误删除的情况,这个时候该如何              快速.有效地恢复数 ...

  8. 使用Team Explorer Everywhere (TEE) 2015 SDK获取团队项目的签入策略

    TFS的代码签入策略与IDE工具紧密相关,例如Visual Studio中设置的签入策略,只会影响Visual Studio的团队资源管理器:如果需要在Eclipse的TEE中启用签入策略,你还需要在 ...

  9. JAVA—IO操作

    一.JAVA I/O 输入输出流 1:编码问题 2:File类的使用 3:RandomAccessFile的使用 4:字节流的使用 5:字符流的使用 6:对象的序列化和反序列化 2: file类的使用 ...

  10. 如何处理加括号的四则混合运算表达式——基于二叉树的实现(Eclipse平台 Java版)

    记得上<数据结构>课程时,利用栈的特性解决过四则混合运算表达式.而如今在编写小型关系数据库的时候,编译部分要处理where后面的逻辑表达式——检查语法正确与否的同时,还要将信息传给下一个接 ...