Loading media/libmedia/AudioTrack.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -335,6 +335,11 @@ status_t AudioTrack::set( ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST); } // force direct flag if HW A/V sync requested if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) { flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); } if (flags & AUDIO_OUTPUT_FLAG_DIRECT) { if (audio_is_linear_pcm(format)) { mFrameSize = channelCount * audio_bytes_per_sample(format); Loading services/audioflinger/Threads.cpp +106 −21 Original line number Diff line number Diff line Loading @@ -1197,6 +1197,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mScreenState(AudioFlinger::mScreenState), // index 0 is reserved for normal mixer's submix mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1), mHwSupportsPause(false), mHwPaused(false), mFlushPending(false), // mLatchD, mLatchQ, mLatchDValid(false), mLatchQValid(false) { Loading Loading @@ -1847,6 +1848,19 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() } } mHwSupportsPause = false; if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) { if (mOutput->stream->pause != NULL) { if (mOutput->stream->resume != NULL) { mHwSupportsPause = true; } else { ALOGW("direct output implements pause but not resume"); } } else if (mOutput->stream->resume != NULL) { ALOGW("direct output implements resume but not pause"); } } // Calculate size of normal sink buffer relative to the HAL output buffer size double multiplier = 1.0; if (mType == MIXER && (kUseFastMixer == FastMixer_Static || Loading Loading @@ -3078,6 +3092,7 @@ void AudioFlinger::PlaybackThread::threadLoop_standby() mCallbackThread->setWriteBlocked(mWriteAckSequence); mCallbackThread->setDraining(mDrainSequence); } mHwPaused = false; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() Loading Loading @@ -3990,6 +4005,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep { size_t count = mActiveTracks.size(); mixer_state mixerStatus = MIXER_IDLE; bool doHwPause = false; bool doHwResume = false; bool flushPending = false; // find out which tracks need to be processed for (size_t i = 0; i < count; i++) { Loading @@ -4008,6 +4026,28 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep sp<Track> l = mLatestActiveTrack.promote(); bool last = l.get() == track; if (mHwSupportsPause && track->isPausing()) { track->setPaused(); if (last && !mHwPaused) { doHwPause = true; mHwPaused = true; } tracksToRemove->add(track); } else if (track->isFlushPending()) { track->flushAck(); if (last) { flushPending = true; } } else if (mHwSupportsPause && track->isResumePending()){ track->resumeAck(); if (last) { if (mHwPaused) { doHwResume = true; mHwPaused = false; } } } // The first time a track is added we wait // for all its buffers to be filled before processing it. // Allow draining the buffer in case the client Loading @@ -4031,8 +4071,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mFillingUpStatus = Track::FS_ACTIVE; // make sure processVolume_l() will apply new volume even if 0 mLeftVolFloat = mRightVolFloat = -1.0; if (track->mState == TrackBase::RESUMING) { track->mState = TrackBase::ACTIVE; if (!mHwSupportsPause) { track->resumeAck(); } } Loading Loading @@ -4095,6 +4135,30 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } } // if an active track did not command a flush, check for pending flush on stopped tracks if (!flushPending) { for (size_t i = 0; i < mTracks.size(); i++) { if (mTracks[i]->isFlushPending()) { mTracks[i]->flushAck(); flushPending = true; } } } // make sure the pause/flush/resume sequence is executed in the right order. // If a flush is pending and a track is active but the HW is not paused, force a HW pause // before flush and then resume HW. This can happen in case of pause/flush/resume // if resume is received before pause is executed. if (mHwSupportsPause && !mStandby && (doHwPause || (flushPending && !mHwPaused && (count != 0)))) { mOutput->stream->pause(mOutput->stream); } if (flushPending) { flushHw_l(); } if (mHwSupportsPause && !mStandby && doHwResume) { mOutput->stream->resume(mOutput->stream); } // remove all the tracks that need to be... removeTracks_l(*tracksToRemove); Loading Loading @@ -4127,6 +4191,11 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix() void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() { // do not write to HAL when paused if (mHwPaused) { sleepTime = idleSleepTime; return; } if (sleepTime == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { sleepTime = activeSleepTime; Loading @@ -4139,6 +4208,38 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() } } void AudioFlinger::DirectOutputThread::threadLoop_exit() { { Mutex::Autolock _l(mLock); bool flushPending = false; for (size_t i = 0; i < mTracks.size(); i++) { if (mTracks[i]->isFlushPending()) { mTracks[i]->flushAck(); flushPending = true; } } if (flushPending) { flushHw_l(); } } PlaybackThread::threadLoop_exit(); } // must be called with thread mutex locked bool AudioFlinger::DirectOutputThread::shouldStandby_l() { bool trackPaused = false; // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack // after a timeout and we will enter standby then. if (mTracks.size() > 0) { trackPaused = mTracks[mTracks.size() - 1]->isPaused(); } return !mStandby && !trackPaused; } // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused, audio_format_t format __unused, int sessionId __unused) Loading Loading @@ -4248,9 +4349,11 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() void AudioFlinger::DirectOutputThread::flushHw_l() { if (mOutput->stream->flush != NULL) if (mOutput->stream->flush != NULL) { mOutput->stream->flush(mOutput->stream); } mHwPaused = false; } // ---------------------------------------------------------------------------- Loading Loading @@ -4358,8 +4461,6 @@ void AudioFlinger::AsyncCallbackThread::resetDraining() AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, uint32_t device) : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD), mHwPaused(false), mFlushPending(false), mPausedBytesRemaining(0) { //FIXME: mStandby should be set to true by ThreadBase constructor Loading Loading @@ -4596,21 +4697,6 @@ bool AudioFlinger::OffloadThread::waitingAsyncCallback_l() return false; } // must be called with thread mutex locked bool AudioFlinger::OffloadThread::shouldStandby_l() { bool trackPaused = false; // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack // after a timeout and we will enter standby then. if (mTracks.size() > 0) { trackPaused = mTracks[mTracks.size() - 1]->isPaused(); } return !mStandby && !trackPaused; } bool AudioFlinger::OffloadThread::waitingAsyncCallback() { Mutex::Autolock _l(mLock); Loading @@ -4625,7 +4711,6 @@ void AudioFlinger::OffloadThread::flushHw_l() mBytesRemaining = 0; mPausedWriteLength = 0; mPausedBytesRemaining = 0; mHwPaused = false; if (mUseAsyncWrite) { // discard any pending drain or write ack by incrementing sequence Loading services/audioflinger/Threads.h +5 −4 Original line number Diff line number Diff line Loading @@ -809,7 +809,9 @@ public: protected: // accessed by both binder threads and within threadLoop(), lock on mutex needed unsigned mFastTrackAvailMask; // bit i set if fast track [i] is available bool mHwSupportsPause; bool mHwPaused; bool mFlushPending; private: // timestamp latch: // D input is written by threadLoop_write while mutex is unlocked, and read while locked Loading Loading @@ -910,6 +912,8 @@ protected: virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove); virtual void threadLoop_mix(); virtual void threadLoop_sleepTime(); virtual void threadLoop_exit(); virtual bool shouldStandby_l(); // volumes last sent to audio HAL with stream->set_volume() float mLeftVolFloat; Loading Loading @@ -940,12 +944,9 @@ protected: virtual bool waitingAsyncCallback(); virtual bool waitingAsyncCallback_l(); virtual bool shouldStandby_l(); virtual void onAddNewTrack_l(); private: bool mHwPaused; bool mFlushPending; size_t mPausedWriteLength; // length in bytes of write interrupted by pause size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume wp<Track> mPreviousTrack; // used to detect track switch Loading services/audioflinger/Tracks.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -823,12 +823,11 @@ void AudioFlinger::PlaybackThread::Track::flush() // this will be done by prepareTracks_l() when the track is stopped. // prepareTracks_l() will see mState == FLUSHED, then // remove from active track list, reset(), and trigger presentation complete if (isDirect()) { mFlushHwPending = true; } if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); if (thread->type() == ThreadBase::DIRECT) { DirectOutputThread *t = (DirectOutputThread *)playbackThread; t->flushHw_l(); } } } // Prevent flush being lost if the track is flushed and then resumed Loading @@ -841,7 +840,7 @@ void AudioFlinger::PlaybackThread::Track::flush() // must be called with thread lock held void AudioFlinger::PlaybackThread::Track::flushAck() { if (!isOffloaded()) if (!isOffloaded() && !isDirect()) return; mFlushHwPending = false; Loading Loading
media/libmedia/AudioTrack.cpp +5 −0 Original line number Diff line number Diff line Loading @@ -335,6 +335,11 @@ status_t AudioTrack::set( ((flags | AUDIO_OUTPUT_FLAG_DIRECT) & ~AUDIO_OUTPUT_FLAG_FAST); } // force direct flag if HW A/V sync requested if ((flags & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0) { flags = (audio_output_flags_t)(flags | AUDIO_OUTPUT_FLAG_DIRECT); } if (flags & AUDIO_OUTPUT_FLAG_DIRECT) { if (audio_is_linear_pcm(format)) { mFrameSize = channelCount * audio_bytes_per_sample(format); Loading
services/audioflinger/Threads.cpp +106 −21 Original line number Diff line number Diff line Loading @@ -1197,6 +1197,7 @@ AudioFlinger::PlaybackThread::PlaybackThread(const sp<AudioFlinger>& audioFlinge mScreenState(AudioFlinger::mScreenState), // index 0 is reserved for normal mixer's submix mFastTrackAvailMask(((1 << FastMixerState::kMaxFastTracks) - 1) & ~1), mHwSupportsPause(false), mHwPaused(false), mFlushPending(false), // mLatchD, mLatchQ, mLatchDValid(false), mLatchQValid(false) { Loading Loading @@ -1847,6 +1848,19 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() } } mHwSupportsPause = false; if (mOutput->flags & AUDIO_OUTPUT_FLAG_DIRECT) { if (mOutput->stream->pause != NULL) { if (mOutput->stream->resume != NULL) { mHwSupportsPause = true; } else { ALOGW("direct output implements pause but not resume"); } } else if (mOutput->stream->resume != NULL) { ALOGW("direct output implements resume but not pause"); } } // Calculate size of normal sink buffer relative to the HAL output buffer size double multiplier = 1.0; if (mType == MIXER && (kUseFastMixer == FastMixer_Static || Loading Loading @@ -3078,6 +3092,7 @@ void AudioFlinger::PlaybackThread::threadLoop_standby() mCallbackThread->setWriteBlocked(mWriteAckSequence); mCallbackThread->setDraining(mDrainSequence); } mHwPaused = false; } void AudioFlinger::PlaybackThread::onAddNewTrack_l() Loading Loading @@ -3990,6 +4005,9 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep { size_t count = mActiveTracks.size(); mixer_state mixerStatus = MIXER_IDLE; bool doHwPause = false; bool doHwResume = false; bool flushPending = false; // find out which tracks need to be processed for (size_t i = 0; i < count; i++) { Loading @@ -4008,6 +4026,28 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep sp<Track> l = mLatestActiveTrack.promote(); bool last = l.get() == track; if (mHwSupportsPause && track->isPausing()) { track->setPaused(); if (last && !mHwPaused) { doHwPause = true; mHwPaused = true; } tracksToRemove->add(track); } else if (track->isFlushPending()) { track->flushAck(); if (last) { flushPending = true; } } else if (mHwSupportsPause && track->isResumePending()){ track->resumeAck(); if (last) { if (mHwPaused) { doHwResume = true; mHwPaused = false; } } } // The first time a track is added we wait // for all its buffers to be filled before processing it. // Allow draining the buffer in case the client Loading @@ -4031,8 +4071,8 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep track->mFillingUpStatus = Track::FS_ACTIVE; // make sure processVolume_l() will apply new volume even if 0 mLeftVolFloat = mRightVolFloat = -1.0; if (track->mState == TrackBase::RESUMING) { track->mState = TrackBase::ACTIVE; if (!mHwSupportsPause) { track->resumeAck(); } } Loading Loading @@ -4095,6 +4135,30 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep } } // if an active track did not command a flush, check for pending flush on stopped tracks if (!flushPending) { for (size_t i = 0; i < mTracks.size(); i++) { if (mTracks[i]->isFlushPending()) { mTracks[i]->flushAck(); flushPending = true; } } } // make sure the pause/flush/resume sequence is executed in the right order. // If a flush is pending and a track is active but the HW is not paused, force a HW pause // before flush and then resume HW. This can happen in case of pause/flush/resume // if resume is received before pause is executed. if (mHwSupportsPause && !mStandby && (doHwPause || (flushPending && !mHwPaused && (count != 0)))) { mOutput->stream->pause(mOutput->stream); } if (flushPending) { flushHw_l(); } if (mHwSupportsPause && !mStandby && doHwResume) { mOutput->stream->resume(mOutput->stream); } // remove all the tracks that need to be... removeTracks_l(*tracksToRemove); Loading Loading @@ -4127,6 +4191,11 @@ void AudioFlinger::DirectOutputThread::threadLoop_mix() void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() { // do not write to HAL when paused if (mHwPaused) { sleepTime = idleSleepTime; return; } if (sleepTime == 0) { if (mMixerStatus == MIXER_TRACKS_ENABLED) { sleepTime = activeSleepTime; Loading @@ -4139,6 +4208,38 @@ void AudioFlinger::DirectOutputThread::threadLoop_sleepTime() } } void AudioFlinger::DirectOutputThread::threadLoop_exit() { { Mutex::Autolock _l(mLock); bool flushPending = false; for (size_t i = 0; i < mTracks.size(); i++) { if (mTracks[i]->isFlushPending()) { mTracks[i]->flushAck(); flushPending = true; } } if (flushPending) { flushHw_l(); } } PlaybackThread::threadLoop_exit(); } // must be called with thread mutex locked bool AudioFlinger::DirectOutputThread::shouldStandby_l() { bool trackPaused = false; // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack // after a timeout and we will enter standby then. if (mTracks.size() > 0) { trackPaused = mTracks[mTracks.size() - 1]->isPaused(); } return !mStandby && !trackPaused; } // getTrackName_l() must be called with ThreadBase::mLock held int AudioFlinger::DirectOutputThread::getTrackName_l(audio_channel_mask_t channelMask __unused, audio_format_t format __unused, int sessionId __unused) Loading Loading @@ -4248,9 +4349,11 @@ void AudioFlinger::DirectOutputThread::cacheParameters_l() void AudioFlinger::DirectOutputThread::flushHw_l() { if (mOutput->stream->flush != NULL) if (mOutput->stream->flush != NULL) { mOutput->stream->flush(mOutput->stream); } mHwPaused = false; } // ---------------------------------------------------------------------------- Loading Loading @@ -4358,8 +4461,6 @@ void AudioFlinger::AsyncCallbackThread::resetDraining() AudioFlinger::OffloadThread::OffloadThread(const sp<AudioFlinger>& audioFlinger, AudioStreamOut* output, audio_io_handle_t id, uint32_t device) : DirectOutputThread(audioFlinger, output, id, device, OFFLOAD), mHwPaused(false), mFlushPending(false), mPausedBytesRemaining(0) { //FIXME: mStandby should be set to true by ThreadBase constructor Loading Loading @@ -4596,21 +4697,6 @@ bool AudioFlinger::OffloadThread::waitingAsyncCallback_l() return false; } // must be called with thread mutex locked bool AudioFlinger::OffloadThread::shouldStandby_l() { bool trackPaused = false; // do not put the HAL in standby when paused. AwesomePlayer clear the offloaded AudioTrack // after a timeout and we will enter standby then. if (mTracks.size() > 0) { trackPaused = mTracks[mTracks.size() - 1]->isPaused(); } return !mStandby && !trackPaused; } bool AudioFlinger::OffloadThread::waitingAsyncCallback() { Mutex::Autolock _l(mLock); Loading @@ -4625,7 +4711,6 @@ void AudioFlinger::OffloadThread::flushHw_l() mBytesRemaining = 0; mPausedWriteLength = 0; mPausedBytesRemaining = 0; mHwPaused = false; if (mUseAsyncWrite) { // discard any pending drain or write ack by incrementing sequence Loading
services/audioflinger/Threads.h +5 −4 Original line number Diff line number Diff line Loading @@ -809,7 +809,9 @@ public: protected: // accessed by both binder threads and within threadLoop(), lock on mutex needed unsigned mFastTrackAvailMask; // bit i set if fast track [i] is available bool mHwSupportsPause; bool mHwPaused; bool mFlushPending; private: // timestamp latch: // D input is written by threadLoop_write while mutex is unlocked, and read while locked Loading Loading @@ -910,6 +912,8 @@ protected: virtual mixer_state prepareTracks_l(Vector< sp<Track> > *tracksToRemove); virtual void threadLoop_mix(); virtual void threadLoop_sleepTime(); virtual void threadLoop_exit(); virtual bool shouldStandby_l(); // volumes last sent to audio HAL with stream->set_volume() float mLeftVolFloat; Loading Loading @@ -940,12 +944,9 @@ protected: virtual bool waitingAsyncCallback(); virtual bool waitingAsyncCallback_l(); virtual bool shouldStandby_l(); virtual void onAddNewTrack_l(); private: bool mHwPaused; bool mFlushPending; size_t mPausedWriteLength; // length in bytes of write interrupted by pause size_t mPausedBytesRemaining; // bytes still waiting in mixbuffer after resume wp<Track> mPreviousTrack; // used to detect track switch Loading
services/audioflinger/Tracks.cpp +4 −5 Original line number Diff line number Diff line Loading @@ -823,12 +823,11 @@ void AudioFlinger::PlaybackThread::Track::flush() // this will be done by prepareTracks_l() when the track is stopped. // prepareTracks_l() will see mState == FLUSHED, then // remove from active track list, reset(), and trigger presentation complete if (isDirect()) { mFlushHwPending = true; } if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); if (thread->type() == ThreadBase::DIRECT) { DirectOutputThread *t = (DirectOutputThread *)playbackThread; t->flushHw_l(); } } } // Prevent flush being lost if the track is flushed and then resumed Loading @@ -841,7 +840,7 @@ void AudioFlinger::PlaybackThread::Track::flush() // must be called with thread lock held void AudioFlinger::PlaybackThread::Track::flushAck() { if (!isOffloaded()) if (!isOffloaded() && !isDirect()) return; mFlushHwPending = false; Loading