赞
踩
- //Test case 3: getPlaybackHeadPosition() is 0 after flush();
- @LargeTest
- public void testPlaybackHeadPositionAfterFlush() throws Exception {
- // constants for test
- final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
- final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
- final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
- final int TEST_MODE = AudioTrack.MODE_STREAM;
- final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
-
- //-------- initialization --------------
- int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
- AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
- minBuffSize, TEST_MODE);
- byte data[] = new byte[minBuffSize/2];
- //-------- test --------------
- assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
- track.write(data, 0, data.length);
- track.write(data, 0, data.length);
- track.play();
- Thread.sleep(100);
- track.stop();
- track.flush();
- log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition());
- assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
- //-------- tear down --------------
- track.release();
- }
- //Test case 3: getPlaybackHeadPosition() is 0 after flush();
- @LargeTest
- public void testPlaybackHeadPositionAfterFlush() throws Exception {
- // constants for test
- final String TEST_NAME = "testPlaybackHeadPositionAfterFlush";
- final int TEST_SR = 22050;
- final int TEST_CONF = AudioFormat.CHANNEL_OUT_STEREO;
- final int TEST_FORMAT = AudioFormat.ENCODING_PCM_16BIT;
- final int TEST_MODE = AudioTrack.MODE_STREAM;
- final int TEST_STREAM_TYPE = AudioManager.STREAM_MUSIC;
-
- //-------- initialization --------------
- int minBuffSize = AudioTrack.getMinBufferSize(TEST_SR, TEST_CONF, TEST_FORMAT);
- AudioTrack track = new AudioTrack(TEST_STREAM_TYPE, TEST_SR, TEST_CONF, TEST_FORMAT,
- minBuffSize, TEST_MODE);
- byte data[] = new byte[minBuffSize/2];
- //-------- test --------------
- assumeTrue(TEST_NAME, track.getState() == AudioTrack.STATE_INITIALIZED);
- track.write(data, 0, data.length);
- track.write(data, 0, data.length);
- track.play();
- Thread.sleep(100);
- track.stop();
- // ++++++++++++++++++++++++++++stop++++++++++++++++++++++++++++++++++++
- /**
- * Stops playing the audio data.
- * @throws IllegalStateException
- */
- public void stop()
- throws IllegalStateException {
- if (mState != STATE_INITIALIZED) {
- throw(new IllegalStateException("stop() called on uninitialized AudioTrack."));
- }
-
-
- // stop playing
- synchronized(mPlayStateLock) {
- native_stop();
- // ++++++++++++++++++++++++++++++android_media_AudioTrack_stop++++++++++++++++++++++++++++++++++
- static void
- android_media_AudioTrack_stop(JNIEnv *env, jobject thiz)
- {
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve AudioTrack pointer for stop()");
- return;
- }
-
-
- lpTrack->stop();
- // +++++++++++++++++++++++++++++++AudioTrack::stop+++++++++++++++++++++++++++++++++
- void AudioTrack::stop()
- {
- // mAudioTrackThread在函数AudioTrack::set中被赋值。
- // mAudioTrackThread = new AudioTrackThread(*this, threadCanCallJava);
- sp<AudioTrackThread> t = mAudioTrackThread;
-
-
- LOGV("stop %p", this);
- if (t != 0) {
- t->mLock.lock();
- }
-
-
- if (android_atomic_and(~1, &mActive) == 1) {
- mCblk->cv.signal();
- // mAudioTrack在函数AudioTrack::createTrack中被赋值,其最终指向的其实是一个TrackHandle对象
- mAudioTrack->stop();
- // ++++++++++++++++++++++++++++++AudioFlinger::TrackHandle::stop++++++++++++++++++++++++++++++++++
- void AudioFlinger::TrackHandle::stop() {
- mTrack->stop();
- // +++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::stop+++++++++++++++++++++++++++++++++++
- void AudioFlinger::PlaybackThread::Track::stop()
- {
- LOGV("stop(%d), calling thread %d", mName, IPCThreadState::self()->getCallingPid());
- // 在Track的构造函数中赋值,指向创建该Track对象的PlaybackThread
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- Mutex::Autolock _l(thread->mLock);
- int state = mState;
- if (mState > STOPPED) {
- // ++++++++++++++++++++++++++++++++track_state++++++++++++++++++++++++++++++++
- enum track_state {
- IDLE,
- TERMINATED,
- STOPPED,
- RESUMING,
- ACTIVE,
- PAUSING,
- PAUSED
- };
- // --------------------------------track_state--------------------------------
- mState = STOPPED;
- // If the track is not active (PAUSED and buffers full), flush buffers
- PlaybackThread *playbackThread = (PlaybackThread *)thread.get();
- if (playbackThread->mActiveTracks.indexOf(this) < 0) {
- reset();
- // ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::reset++++++++++++++++++++++++++++++++++
- void AudioFlinger::PlaybackThread::Track::reset()
- {
- // Do not reset twice to avoid discarding data written just after a flush and before
- // the audioflinger thread detects the track is stopped.
- if (!mResetDone) {
- TrackBase::reset();
- // ++++++++++++++++++++++++++++++AudioFlinger::ThreadBase::TrackBase::reset++++++++++++++++++++++++++++++++++
- void AudioFlinger::ThreadBase::TrackBase::reset() {
- audio_track_cblk_t* cblk = this->cblk();
-
-
- cblk->user = 0;
- cblk->server = 0;
- cblk->userBase = 0;
- cblk->serverBase = 0;
- mFlags &= (uint32_t)(~SYSTEM_FLAGS_MASK);
- LOGV("TrackBase::reset");
- }
- // ------------------------------AudioFlinger::ThreadBase::TrackBase::reset----------------------------------
- // Force underrun condition to avoid false underrun callback until first data is
- // written to buffer
- mCblk->flags |= CBLK_UNDERRUN_ON;
- mCblk->flags &= ~CBLK_FORCEREADY_MSK;
- mFillingUpStatus = FS_FILLING;
- mResetDone = true;
- }
- }
- // ------------------------------AudioFlinger::PlaybackThread::Track::reset----------------------------------
- }
- LOGV("(> STOPPED) => STOPPED (%d) on thread %p", mName, playbackThread);
- }
- if (!isOutputTrack() && (state == ACTIVE || state == RESUMING)) {
- thread->mLock.unlock();
- AudioSystem::stopOutput(thread->id(),
- (AudioSystem::stream_type)mStreamType,
- mSessionId);
- // ++++++++++++++++++++++++++++++AudioSystem::stopOutput++++++++++++++++++++++++++++++++++
- status_t AudioSystem::stopOutput(audio_io_handle_t output,
- AudioSystem::stream_type stream,
- int session)
- {
- const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
- if (aps == 0) return PERMISSION_DENIED;
- return aps->stopOutput(output, stream, session);
- // +++++++++++++++++++++++++++++++++AudioPolicyService::stopOutput+++++++++++++++++++++++++++++++
- status_t AudioPolicyService::stopOutput(audio_io_handle_t output,
- AudioSystem::stream_type stream,
- int session)
- {
- if (mpPolicyManager == NULL) {
- return NO_INIT;
- }
- LOGV("stopOutput() tid %d", gettid());
- Mutex::Autolock _l(mLock);
- return mpPolicyManager->stopOutput(output, stream, session);
- // ++++++++++++++++++++++++++++++AudioPolicyManagerBase::stopOutput++++++++++++++++++++++++++++++++++
- status_t AudioPolicyManagerBase::stopOutput(audio_io_handle_t output,
- AudioSystem::stream_type stream,
- int session)
- {
- LOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- LOGW("stopOutput() unknow output %d", output);
- return BAD_VALUE;
- }
-
-
- AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
- routing_strategy strategy = getStrategy((AudioSystem::stream_type)stream);
-
-
- // handle special case for sonification while in call
- if (isInCall()) {
- handleIncallSonification(stream, false, false);
- }
-
-
- if (outputDesc->mRefCount[stream] > 0) {
- // decrement usage count of this stream on the output
- outputDesc->changeRefCount(stream, -1);
- // ++++++++++++++++++++++++++++AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount++++++++++++++++++++++++++++++++++++
- void AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount(AudioSystem::stream_type stream, int delta)
- {
- // forward usage count change to attached outputs
- if (isDuplicated()) {
- mOutput1->changeRefCount(stream, delta);
- mOutput2->changeRefCount(stream, delta);
- }
- if ((delta + (int)mRefCount[stream]) < 0) {
- LOGW("changeRefCount() invalid delta %d for stream %d, refCount %d", delta, stream, mRefCount[stream]);
- mRefCount[stream] = 0;
- return;
- }
- // 函数AudioPolicyManagerBase::AudioOutputDescriptor::refCount会使用mRefCount
- mRefCount[stream] += delta;
- // +++++++++++++++++++++++++++++AudioPolicyManagerBase::AudioOutputDescriptor::refCount+++++++++++++++++++++++++++++++++++
- uint32_t AudioPolicyManagerBase::AudioOutputDescriptor::refCount()
- {
- uint32_t refcount = 0;
- for (int i = 0; i < (int)AudioSystem::NUM_STREAM_TYPES; i++) {
- refcount += mRefCount[i];
- }
- return refcount;
- }
- // 函数AudioPolicyManagerBase::releaseOutput中有调用函数AudioPolicyManagerBase::AudioOutputDescriptor::refCount。
- // +++++++++++++++++++++++++++++AudioPolicyManagerBase::releaseOutput+++++++++++++++++++++++++++++++++++
- void AudioPolicyManagerBase::releaseOutput(audio_io_handle_t output)
- {
- LOGV("releaseOutput() %d", output);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- LOGW("releaseOutput() releasing unknown output %d", output);
- return;
- }
-
-
- #ifdef AUDIO_POLICY_TEST
- int testIndex = testOutputIndex(output);
- if (testIndex != 0) {
- AudioOutputDescriptor *outputDesc = mOutputs.valueAt(index);
- if (outputDesc->refCount() == 0) {
- mpClientInterface->closeOutput(output);
- delete mOutputs.valueAt(index);
- mOutputs.removeItem(output);
- mTestOutputs[testIndex] = 0;
- }
- return;
- }
- #endif //AUDIO_POLICY_TEST
-
-
- // 如果没定义AUDIO_POLICY_TEST,只对设置了OUTPUT_FLAG_DIRECT标志的output做delete处理
- // 原因,其实在以前我们看AudioPolicyManagerBase::getOutput函数时已经看到了,
- // 在get output的时候,只有需要一个direct output的时候,才会调用函数AudioPolicyService::openOutput函数来打开一个output
- // 否则,只是将成员变量(在构造函数中打开的output)返回
- // 当然,我们没有考虑AUDIO_POLICY_TEST时的情况
- if (mOutputs.valueAt(index)->mFlags & AudioSystem::OUTPUT_FLAG_DIRECT) {
- // ++++++++++++++++++++++++++++++output_flags++++++++++++++++++++++++++++++++++
- // request to open a direct output with getOutput() (by opposition to sharing an output with other AudioTracks)
- enum output_flags {
- OUTPUT_FLAG_INDIRECT = 0x0,
- OUTPUT_FLAG_DIRECT = 0x1
- };
- // ------------------------------output_flags----------------------------------
- mpClientInterface->closeOutput(output);
- // +++++++++++++++++++++++++++++AudioPolicyService::closeOutput+++++++++++++++++++++++++++++++++++
- status_t AudioPolicyService::closeOutput(audio_io_handle_t output)
- {
- sp<IAudioFlinger> af = AudioSystem::get_audio_flinger();
- if (af == 0) return PERMISSION_DENIED;
-
-
- return af->closeOutput(output);
- // +++++++++++++++++++++++++++AudioFlinger::closeOutput++++++++++++++++++++++++++++++++++++
- status_t AudioFlinger::closeOutput(int output)
- {
- // keep strong reference on the playback thread so that
- // it is not destroyed while exit() is executed
- sp <PlaybackThread> thread;
- {
- Mutex::Autolock _l(mLock);
- thread = checkPlaybackThread_l(output);
- if (thread == NULL) {
- return BAD_VALUE;
- }
-
-
- LOGV("closeOutput() %d", output);
-
-
- // 如果thread 为mixer
- // 删除所有DUPLICATING thread中包含的该thread
- if (thread->type() == PlaybackThread::MIXER) {
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (mPlaybackThreads.valueAt(i)->type() == PlaybackThread::DUPLICATING) {
- DuplicatingThread *dupThread = (DuplicatingThread *)mPlaybackThreads.valueAt(i).get();
- dupThread->removeOutputTrack((MixerThread *)thread.get());
- }
- }
- }
- void *param2 = 0;
- audioConfigChanged_l(AudioSystem::OUTPUT_CLOSED, output, param2);
- mPlaybackThreads.removeItem(output);
- }
- thread->exit();
- // ++++++++++++++++++++++++++++AudioFlinger::ThreadBase::exit++++++++++++++++++++++++++++++++++++
- void AudioFlinger::ThreadBase::exit()
- {
- // keep a strong ref on ourself so that we wont get
- // destroyed in the middle of requestExitAndWait()
- sp <ThreadBase> strongMe = this;
-
-
- LOGV("ThreadBase::exit");
- {
- AutoMutex lock(&mLock);
- mExiting = true;
- requestExit();
- // +++++++++++++++++++++++++++++Thread::requestExit+++++++++++++++++++++++++++++++++++
- void Thread::requestExit()
- {
- // threadloop函数中会判断该成员变量,以判断是否要结束线程
- mExitPending = true;
- }
- // -----------------------------Thread::requestExit----------------------------------
- mWaitWorkCV.signal();
- }
- requestExitAndWait();
- // +++++++++++++++++++++++++++++Thread::requestExitAndWait+++++++++++++++++++++++++++++++++++
- status_t Thread::requestExitAndWait()
- {
- if (mThread == getThreadId()) {
- LOGW(
- "Thread (this=%p): don't call waitForExit() from this "
- "Thread object's thread. It's a guaranteed deadlock!",
- this);
-
-
- return WOULD_BLOCK;
- }
-
- requestExit();
-
-
- Mutex::Autolock _l(mLock);
- while (mRunning == true) {
- mThreadExitedCondition.wait(mLock);
- }
- mExitPending = false;
-
-
- return mStatus;
- }
- // -----------------------------Thread::requestExitAndWait-----------------------------------
- }
- // ----------------------------AudioFlinger::ThreadBase::exit------------------------------------
-
-
- if (thread->type() != PlaybackThread::DUPLICATING) {
- // output是在函数AudioFlinger::openOutput中调用函数mAudioHardware->openOutputStream打开的。
- mAudioHardware->closeOutputStream(thread->getOutput());
- // +++++++++++++++++++++++++++AudioHardwareALSA::closeOutputStream+++++++++++++++++++++++++++++++++++++
- void
- AudioHardwareALSA::closeOutputStream(AudioStreamOut* out)
- {
- AutoMutex lock(mLock);
- delete out;
- }
- // ---------------------------AudioHardwareALSA::closeOutputStream-------------------------------------
- }
- return NO_ERROR;
- }
- // ----------------------------AudioFlinger::closeOutput------------------------------------
- }
- // -----------------------------AudioPolicyService::closeOutput-----------------------------------
- delete mOutputs.valueAt(index);
- mOutputs.removeItem(output);
- }
- }
- // -----------------------------AudioPolicyManagerBase::releaseOutput-----------------------------------
- // -----------------------------AudioPolicyManagerBase::AudioOutputDescriptor::refCount-----------------------------------
- LOGV("changeRefCount() stream %d, count %d", stream, mRefCount[stream]);
- }
- // ----------------------------AudioPolicyManagerBase::AudioOutputDescriptor::changeRefCount------------------------------------
- // store time at which the last music track was stopped - see computeVolume()
- if (stream == AudioSystem::MUSIC) {
- mMusicStopTime = systemTime();
- }
-
-
- setOutputDevice(output, getNewDevice(output));
-
-
- #ifdef WITH_A2DP
- if (mA2dpOutput != 0 && !a2dpUsedForSonification() &&
- strategy == STRATEGY_SONIFICATION) {
- setStrategyMute(STRATEGY_MEDIA,
- false,
- mA2dpOutput,
- mOutputs.valueFor(mHardwareOutput)->mLatency*2);
- }
- #endif
- if (output != mHardwareOutput) {
- setOutputDevice(mHardwareOutput, getNewDevice(mHardwareOutput), true);
- }
- return NO_ERROR;
- } else {
- LOGW("stopOutput() refcount is already 0 for output %d", output);
- return INVALID_OPERATION;
- }
- }
- // ------------------------------AudioPolicyManagerBase::stopOutput----------------------------------
- }
- // ---------------------------------AudioPolicyService::stopOutput-------------------------------
- }
- // ------------------------------AudioSystem::stopOutput----------------------------------
- thread->mLock.lock();
- }
- }
- }
- // -----------------------------AudioFlinger::PlaybackThread::Track::stop-----------------------------------
- }
- // ------------------------------AudioFlinger::TrackHandle::stop----------------------------------
- // Cancel loops (If we are in the middle of a loop, playback
- // would not stop until loopCount reaches 0).
- setLoop(0, 0, 0);
- // +++++++++++++++++++++++++++++AudioTrack::setLoop+++++++++++++++++++++++++++++++++++
- status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount)
- {
- audio_track_cblk_t* cblk = mCblk;
-
-
- Mutex::Autolock _l(cblk->lock);
-
-
- if (loopCount == 0) {
- cblk->loopStart = ULLONG_MAX;
- cblk->loopEnd = ULLONG_MAX;
- cblk->loopCount = 0;
- mLoopCount = 0;
- return NO_ERROR;
- }
-
-
- if (loopStart >= loopEnd ||
- loopEnd - loopStart > cblk->frameCount) {
- LOGE("setLoop invalid value: loopStart %d, loopEnd %d, loopCount %d, framecount %d, user %lld", loopStart, loopEnd, loopCount, cblk->frameCount, cblk->user);
- return BAD_VALUE;
- }
-
-
- if ((mSharedBuffer != 0) && (loopEnd > cblk->frameCount)) {
- LOGE("setLoop invalid value: loop markers beyond data: loopStart %d, loopEnd %d, framecount %d",
- loopStart, loopEnd, cblk->frameCount);
- return BAD_VALUE;
- }
-
-
- cblk->loopStart = loopStart;
- cblk->loopEnd = loopEnd;
- cblk->loopCount = loopCount;
- mLoopCount = loopCount;
-
-
- return NO_ERROR;
- }
- // -----------------------------AudioTrack::setLoop-----------------------------------
- // the playback head position will reset to 0, so if a marker is set, we need
- // to activate it again
- mMarkerReached = false;
- // Force flush if a shared buffer is used otherwise audioflinger
- // will not stop before end of buffer is reached.
- if (mSharedBuffer != 0) {
- flush();
- // ++++++++++++++++++++++++++++AudioTrack::flush++++++++++++++++++++++++++++++++++++
- void AudioTrack::flush()
- {
- LOGV("flush");
-
-
- // clear playback marker and periodic update counter
- mMarkerPosition = 0;
- mMarkerReached = false;
- mUpdatePeriod = 0;
-
-
-
-
- if (!mActive) {
- mAudioTrack->flush();
- // ++++++++++++++++++++++++++++++AudioFlinger::TrackHandle::flush++++++++++++++++++++++++++++++++++
- void AudioFlinger::TrackHandle::flush() {
- mTrack->flush();
- // ++++++++++++++++++++++++++++++AudioFlinger::PlaybackThread::Track::flush++++++++++++++++++++++++++++++++++
- void AudioFlinger::PlaybackThread::Track::flush()
- {
- LOGV("flush(%d)", mName);
- sp<ThreadBase> thread = mThread.promote();
- if (thread != 0) {
- Mutex::Autolock _l(thread->mLock);
- if (mState != STOPPED && mState != PAUSED && mState != PAUSING) {
- return;
- }
- // No point remaining in PAUSED state after a flush => go to
- // STOPPED state
- mState = STOPPED;
-
-
- mCblk->lock.lock();
- // NOTE: reset() will reset cblk->user and cblk->server with
- // the risk that at the same time, the AudioMixer is trying to read
- // data. In this case, getNextBuffer() would return a NULL pointer
- // as audio buffer => the AudioMixer code MUST always test that pointer
- // returned by getNextBuffer() is not NULL!
- // reset函数在stop函数中已经看过
- reset();
- mCblk->lock.unlock();
- }
- }
- // ------------------------------AudioFlinger::PlaybackThread::Track::flush----------------------------------
- }
- // ------------------------------AudioFlinger::TrackHandle::flush----------------------------------
- // Release AudioTrack callback thread in case it was waiting for new buffers
- // in AudioTrack::obtainBuffer()
- mCblk->cv.signal();
- }
- }
- // ----------------------------AudioTrack::flush------------------------------------
- }
- if (t != 0) {
- t->requestExit();
- } else {
- setpriority(PRIO_PROCESS, 0, ANDROID_PRIORITY_NORMAL);
- }
- }
-
-
- if (t != 0) {
- t->mLock.unlock();
- }
- }
- // -------------------------------AudioTrack::stop---------------------------------
- }
- // ------------------------------android_media_AudioTrack_stop----------------------------------
- mPlayState = PLAYSTATE_STOPPED;
- }
- }
- // ----------------------------stop------------------------------------
- track.flush();
- // ++++++++++++++++++++++++++++flush++++++++++++++++++++++++++++++++++++
- /**
- * Flushes the audio data currently queued for playback.
- */
-
-
- public void flush() {
- if (mState == STATE_INITIALIZED) {
- // flush the data in native layer
- native_flush();
- // ++++++++++++++++++++++++++++android_media_AudioTrack_flush++++++++++++++++++++++++++++++++++++
- static void
- android_media_AudioTrack_flush(JNIEnv *env, jobject thiz)
- {
- AudioTrack *lpTrack = (AudioTrack *)env->GetIntField(
- thiz, javaAudioTrackFields.nativeTrackInJavaObj);
- if (lpTrack == NULL ) {
- jniThrowException(env, "java/lang/IllegalStateException",
- "Unable to retrieve AudioTrack pointer for flush()");
- return;
- }
-
-
- lpTrack->flush();
- // +++++++++++++++++++++++++++++AudioTrack::flush+++++++++++++++++++++++++++++++++++
- void AudioTrack::flush()
- {
- LOGV("flush");
-
-
- // clear playback marker and periodic update counter
- mMarkerPosition = 0;
- mMarkerReached = false;
- mUpdatePeriod = 0;
-
-
-
-
- if (!mActive) {
- mAudioTrack->flush();
- // ++++++++++++++++++++++++++++AudioFlinger::TrackHandle::flush++++++++++++++++++++++++++++++++++++
- void AudioFlinger::TrackHandle::flush() {
- // 函数AudioFlinger::PlaybackThread::Track::flush在上面已经看过
- mTrack->flush();
- }
- // ----------------------------AudioFlinger::TrackHandle::flush------------------------------------
- // Release AudioTrack callback thread in case it was waiting for new buffers
- // in AudioTrack::obtainBuffer()
- mCblk->cv.signal();
- }
- }
- // -----------------------------AudioTrack::flush-----------------------------------
- }
- // ----------------------------android_media_AudioTrack_flush------------------------------------
- }
-
-
- }
- // ----------------------------flush------------------------------------
- log(TEST_NAME, "position ="+ track.getPlaybackHeadPosition());
- assertTrue(TEST_NAME, track.getPlaybackHeadPosition() == 0);
- //-------- tear down --------------
- track.release();
- }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。