在上一篇文章《(四)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. Zookeeper 源码(五)Leader 选举

    Zookeeper 源码(五)Leader 选举 前面学习了 Zookeeper 服务端的相关细节,其中对于集群启动而言,很重要的一部分就是 Leader 选举,接着就开始深入学习 Leader 选举 ...

  2. Zookeeper 源码(二)序列化组件 Jute

    Zookeeper 源码(二)序列化组件 Jute 一.序列化组件 Jute 对于一个网络通信,首先需要解决的就是对数据的序列化和反序列化处理,在 ZooKeeper 中,使用了Jute 这一序列化组 ...

  3. JAVA array,map 转 json 字符串

    public class User { private String username; private String password; public String getUsername() { ...

  4. 小程序报错Do not have xx handler in current page的解决方法

    看到小程序这一大串的“Do not have bindName handler in current page: pages/card/card. Please make sure that bind ...

  5. WordPress 3.7.1-web截屏插件整合教程-Xproer.ScreenCapture

    插件下载(PHP):wordpress 3.7.1, 说明:由于许多插件可能使用相同钩子,导致冲突,所以提供手支方式整合. 1.上传插件目录. 说明:WordPress 3.7.1 使用的是TinyM ...

  6. 支付宝 iOS SDK 官方下载页面[转]

    from:http://blog.sina.com.cn/s/blog_6f72ff900102v0sw.html 藏得太深了,不得不记下来!     官方页面地址:   https://b.alip ...

  7. Android AR平台

    ARToolkit:https://baike.baidu.com/item/ARToolkit/5726883?fr=aladdin Vuforia:搭建Android AR技术开发环境(Aqume ...

  8. Navicet Mysql数据库电脑本地备份

    Navicet Mysql数据库电脑本地备份 1.打开navicat客户端,连上mysql后,双击左边你想要备份的数据库.点击"计划",再点击"新建批处理作业" ...

  9. 咏南中间件增加WEBSOCKET支持

    咏南中间件增加WEBSOCKET支持

  10. #ifdef __cplusplus extern "C" { #endif 的解释

    好多程序中都会遇到下列代码段: #ifdef __cplusplus extern "C" { #endif /****************** C语法代码段 ******** ...