(五)Audio子系统之AudioRecord.stop
在上一篇文章《(四)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方法了。
由于作者内功有限,若文章中存在错误或不足的地方,还请给位大佬指出,不胜感激!
作者:pngcui
博客园:http://www.cnblogs.com/pngcui/
github:https://github.com/pngcui
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明。