下面我就以Play为例,分析一下从AudioTrack JAVA->JNI->AudioTrack Native的过程:
首先是AudioTrack.java:
//frameworks/base/media/java/android/media/AudioTrack.java
public void play()
throws IllegalStateException {
if (mState != STATE_INITIALIZED) {
throw new IllegalStateException("play() called on uninitialized AudioTrack.");
}
//FIXME use lambda to pass startImpl to superclass
final int delay = getStartDelayMs();
if (delay == 0) {
startImpl();
} else {
new Thread() {
public void run() {
try {
Thread.sleep(delay);
} catch (InterruptedException e) {
e.printStackTrace();
}
baseSetStartDelayMs(0);
try {
startImpl();
} catch (IllegalStateException e) {
// fail silently for a state exception when it is happening after
// a delayed start, as the player state could have changed between the
// call to start() and the execution of startImpl()
}
}
}.start();
}
}
private void startImpl() {
synchronized(mPlayStateLock) {
baseStart();
native_start();
if (mPlayState == PLAYSTATE_PAUSED_STOPPING) {
mPlayState = PLAYSTATE_STOPPING;
} else {
mPlayState = PLAYSTATE_PLAYING;
mOffloadEosPending = false;
}
}
}
代码比较简单,直接调用native_start,通过查询JNI代码android_media_AudioTrack.cpp得出调用的函数是android_media_AudioTrack_start:
//frameworks/base/core/jni/android_media_AudioTrack.cpp
static jint
android_media_AudioTrack_start(JNIEnv *env, jobject thiz)
{
sp<AudioTrack> lpTrack = getAudioTrack(env, thiz);
if (lpTrack == NULL) {
jniThrowException(env, "java/lang/IllegalStateException",
"Unable to retrieve AudioTrack pointer for start()");
return;
}
lpTrack->start();
}
在android_media_AudioTrack_start中调用AudioTrack的start函数:
//frameworks/av/media/libaudioclient/AudioTrack.cpp
status_t AudioTrack::start()
{
AutoMutex lock(mLock);
ALOGV("%s(%d): prior state:%s", __func__, mPortId, stateToString(mState));
if (mState == STATE_ACTIVE) {
return INVALID_OPERATION;
}
mInUnderrun = true;
State previousState = mState;
if (previousState == STATE_PAUSED_STOPPING) {
mState = STATE_STOPPING;
} else {
mState = STATE_ACTIVE;
}
(void) updateAndGetPosition_l();
// save start timestamp
if (isOffloadedOrDirect_l()) {
if (getTimestamp_l(mStartTs) != OK) {
mStartTs.mPosition = 0;
}
} else {
if (getTimestamp_l(&mStartEts) != OK) {
mStartEts.clear();
}
}
mStartNs = systemTime(); // save this for timestamp adjustment after starting.
if (previousState == STATE_STOPPED || previousState == STATE_FLUSHED) {
// reset current position as seen by client to 0
mPosition = 0;
mPreviousTimestampValid = false;
mTimestampStartupGlitchReported = false;
mTimestampRetrogradePositionReported = false;
mTimestampRetrogradeTimeReported = false;
mTimestampStallReported = false;
mTimestampStaleTimeReported = false;
mPreviousLocation = ExtendedTimestamp::LOCATION_INVALID;
if (!isOffloadedOrDirect_l()
&& mStartEts.mTimeNs[ExtendedTimestamp::LOCATION_SERVER] > 0) {
// Server side has consumed something, but is it finished consuming?
// It is possible since flush and stop are asynchronous that the server
// is still active at this point.
ALOGV("%s(%d): server read:%lld cumulative flushed:%lld client written:%lld",
__func__, mPortId,
(long long)(mFramesWrittenServerOffset
+ mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER]),
(long long)mStartEts.mFlushed,
(long long)mFramesWritten);
// mStartEts is already adjusted by mFramesWrittenServerOffset, so we delta adjust.
mFramesWrittenServerOffset -= mStartEts.mPosition[ExtendedTimestamp::LOCATION_SERVER];
}
mFramesWritten = 0;
mProxy->clearTimestamp(); // need new server push for valid timestamp
mMarkerReached = false;
// For offloaded tracks, we don't know if the hardware counters are really zero here,
// since the flush is asynchronous and stop may not fully drain.
// We save the time when the track is started to later verify whether
// the counters are realistic (i.e. start from zero after this time).
mStartFromZeroUs = mStartNs / 1000;
// force refresh of remaining frames by processAudioBuffer() as last
// write before stop could be partial.
mRefreshRemaining = true;
// for static track, clear the old flags when starting from stopped state
if (mSharedBuffer != 0) {
android_atomic_and(
~(CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END),
&mCblk->mFlags);
}
}
mNewPosition = mPosition + mUpdatePeriod;
int32_t flags = android_atomic_and(~(CBLK_STREAM_END_DONE | CBLK_DISABLED), &mCblk->mFlags);
status_t status = NO_ERROR;
if (!(flags & CBLK_INVALID)) {
status = mAudioTrack->start(); //调用IAudioTrack的start
if (status == DEAD_OBJECT) {
flags |= CBLK_INVALID;
}
}
if (flags & CBLK_INVALID) {
status = restoreTrack_l("start");
}
// resume or pause the callback thread as needed.
sp<AudioTrackThread> t = mAudioTrackThread;
if (status == NO_ERROR) {
if (t != 0) {
if (previousState == STATE_STOPPING) {
mProxy->interrupt();
} else {
t->resume();
}
} else {
mPreviousPriority = getpriority(PRIO_PROCESS, 0);
get_sched_policy(0, &mPreviousSchedulingGroup);
androidSetThreadPriority(0, ANDROID_PRIORITY_AUDIO);
}
// Start our local VolumeHandler for restoration purposes.
mVolumeHandler->setStarted();
} else {
ALOGE("%s(%d): status %d", __func__, mPortId, status);
mState = previousState;
if (t != 0) {
if (previousState != STATE_STOPPING) {
t->pause();
}
} else {
setpriority(PRIO_PROCESS, 0, mPreviousPriority);
set_sched_policy(0, mPreviousSchedulingGroup);
}
}
return status;
}
这里最重要的代码就是status = mAudioTrack->start(); ,其中mAudioTrack的定义为sp<IAudioTrack> mAudioTrack;,IAudioTrack接口由AudioFlinger的BnAudioTrack实现, mAudioTrack->start()会调用BnAudioTrack的start函数。
/frameworks/av/media/libaudioclient/IAudioTrack.aidl
interface IAudioTrack {
......
int start();
}
AudioFlinger AudioTrack start
调用AudioFlinger TrackHandler的start方法: