From ab5cdbaf65ca509681d2726aacdf3ac8bfb6b3fa Mon Sep 17 00:00:00 2001 From: Eric Laurent Date: Mon, 9 Jun 2014 17:22:27 -0700 Subject: [PATCH] AudioTrack: add support for compressed audio Add support for compressed audio playback by use of an AudioTrack attached to a direct output thread. Bug: 9428304. Change-Id: I4a61be9cf0e31003ca85935d6e0ee38ca8192e03 --- include/media/AudioTrack.h | 9 ++++ include/media/IAudioFlinger.h | 1 + media/libmedia/AudioTrack.cpp | 67 ++++++++++++++++++++++------- services/audioflinger/PlaybackTracks.h | 1 + services/audioflinger/Threads.cpp | 37 ++++++++++------ services/audioflinger/Tracks.cpp | 6 +-- services/audiopolicy/AudioPolicyManager.cpp | 5 +++ 7 files changed, 95 insertions(+), 31 deletions(-) diff --git a/include/media/AudioTrack.h b/include/media/AudioTrack.h index 5dc77a3515..3492520147 100644 --- a/include/media/AudioTrack.h +++ b/include/media/AudioTrack.h @@ -632,6 +632,8 @@ protected: nsecs_t processAudioBuffer(); bool isOffloaded() const; + bool isDirect() const; + bool isOffloadedOrDirect() const; // caller must hold lock on mLock for all _l methods @@ -648,6 +650,13 @@ protected: bool isOffloaded_l() const { return (mFlags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0; } + bool isOffloadedOrDirect_l() const + { return (mFlags & (AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD| + AUDIO_OUTPUT_FLAG_DIRECT)) != 0; } + + bool isDirect_l() const + { return (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) != 0; } + // Next 4 fields may be changed if IAudioTrack is re-created, but always != 0 sp mAudioTrack; sp mCblkMemory; diff --git a/include/media/IAudioFlinger.h b/include/media/IAudioFlinger.h index c742810906..fc8be2072a 100644 --- a/include/media/IAudioFlinger.h +++ b/include/media/IAudioFlinger.h @@ -50,6 +50,7 @@ public: TRACK_TIMED = 1, // client requests a TimedAudioTrack TRACK_FAST = 2, // client requests a fast AudioTrack or AudioRecord TRACK_OFFLOAD = 4, // client requests offload to hw codec + TRACK_DIRECT = 8, // client requests a direct output }; typedef uint32_t track_flags_t; diff --git a/media/libmedia/AudioTrack.cpp b/media/libmedia/AudioTrack.cpp index 77419f0387..5c82cfbb7d 100644 --- a/media/libmedia/AudioTrack.cpp +++ b/media/libmedia/AudioTrack.cpp @@ -635,7 +635,7 @@ void AudioTrack::getAuxEffectSendLevel(float* level) const status_t AudioTrack::setSampleRate(uint32_t rate) { - if (mIsTimed || isOffloaded()) { + if (mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -666,7 +666,7 @@ uint32_t AudioTrack::getSampleRate() const // sample rate can be updated during playback by the offloaded decoder so we need to // query the HAL and update if needed. // FIXME use Proxy return channel to update the rate from server and avoid polling here - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { if (mOutput != AUDIO_IO_HANDLE_NONE) { uint32_t sampleRate = 0; status_t status = AudioSystem::getSamplingRate(mOutput, &sampleRate); @@ -680,7 +680,7 @@ uint32_t AudioTrack::getSampleRate() const status_t AudioTrack::setLoop(uint32_t loopStart, uint32_t loopEnd, int loopCount) { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -714,7 +714,7 @@ void AudioTrack::setLoop_l(uint32_t loopStart, uint32_t loopEnd, int loopCount) status_t AudioTrack::setMarkerPosition(uint32_t marker) { // The only purpose of setting marker position is to get a callback - if (mCbf == NULL || isOffloaded()) { + if (mCbf == NULL || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -727,7 +727,7 @@ status_t AudioTrack::setMarkerPosition(uint32_t marker) status_t AudioTrack::getMarkerPosition(uint32_t *marker) const { - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return INVALID_OPERATION; } if (marker == NULL) { @@ -743,7 +743,7 @@ status_t AudioTrack::getMarkerPosition(uint32_t *marker) const status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) { // The only purpose of setting position update period is to get a callback - if (mCbf == NULL || isOffloaded()) { + if (mCbf == NULL || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -756,7 +756,7 @@ status_t AudioTrack::setPositionUpdatePeriod(uint32_t updatePeriod) status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const { - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return INVALID_OPERATION; } if (updatePeriod == NULL) { @@ -771,7 +771,7 @@ status_t AudioTrack::getPositionUpdatePeriod(uint32_t *updatePeriod) const status_t AudioTrack::setPosition(uint32_t position) { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } if (position > mFrameCount) { @@ -804,10 +804,10 @@ status_t AudioTrack::getPosition(uint32_t *position) const } AutoMutex lock(mLock); - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { uint32_t dspFrames = 0; - if ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING)) { + if (isOffloaded_l() && ((mState == STATE_PAUSED) || (mState == STATE_PAUSED_STOPPING))) { ALOGV("getPosition called in paused state, return cached position %u", mPausedPosition); *position = mPausedPosition; return NO_ERROR; @@ -842,7 +842,7 @@ status_t AudioTrack::getBufferPosition(uint32_t *position) status_t AudioTrack::reload() { - if (mSharedBuffer == 0 || mIsTimed || isOffloaded()) { + if (mSharedBuffer == 0 || mIsTimed || isOffloadedOrDirect()) { return INVALID_OPERATION; } @@ -1038,6 +1038,10 @@ status_t AudioTrack::createTrack_l(size_t epoch) trackFlags |= IAudioFlinger::TRACK_OFFLOAD; } + if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + trackFlags |= IAudioFlinger::TRACK_DIRECT; + } + size_t temp = frameCount; // temp may be replaced by a revised value of frameCount, // but we will still need the original value also sp track = audioFlinger->createTrack(mStreamType, @@ -1129,6 +1133,16 @@ status_t AudioTrack::createTrack_l(size_t epoch) //return NO_INIT; } } + if (mFlags & AUDIO_OUTPUT_FLAG_DIRECT) { + if (trackFlags & IAudioFlinger::TRACK_DIRECT) { + ALOGV("AUDIO_OUTPUT_FLAG_DIRECT successful"); + } else { + ALOGW("AUDIO_OUTPUT_FLAG_DIRECT denied by server"); + mFlags = (audio_output_flags_t) (mFlags & ~AUDIO_OUTPUT_FLAG_DIRECT); + // FIXME This is a warning, not an error, so don't return error status + //return NO_INIT; + } + } // We retain a copy of the I/O handle, but don't own the reference mOutput = output; @@ -1324,6 +1338,16 @@ ssize_t AudioTrack::write(const void* buffer, size_t userSize, bool blocking) return INVALID_OPERATION; } + if (isDirect()) { + AutoMutex lock(mLock); + int32_t flags = android_atomic_and( + ~(CBLK_UNDERRUN | CBLK_LOOP_CYCLE | CBLK_LOOP_FINAL | CBLK_BUFFER_END), + &mCblk->mFlags); + if (flags & CBLK_INVALID) { + return DEAD_OBJECT; + } + } + if (ssize_t(userSize) < 0 || (buffer == NULL && userSize != 0)) { // Sanity-check: user is most-likely passing an error code, and it would // make the return value ambiguous (actualSize vs error). @@ -1472,7 +1496,7 @@ nsecs_t AudioTrack::processAudioBuffer() // for offloaded tracks restoreTrack_l() will just update the sequence and clear // AudioSystem cache. We should not exit here but after calling the callback so // that the upper layers can recreate the track - if (!isOffloaded_l() || (mSequence == mObservedSequence)) { + if (!isOffloadedOrDirect_l() || (mSequence == mObservedSequence)) { status_t status = restoreTrack_l("processAudioBuffer"); mLock.unlock(); // Run again immediately, but with a new IAudioTrack @@ -1598,7 +1622,7 @@ nsecs_t AudioTrack::processAudioBuffer() mObservedSequence = sequence; mCbf(EVENT_NEW_IAUDIOTRACK, mUserData, NULL); // for offloaded tracks, just wait for the upper layers to recreate the track - if (isOffloaded()) { + if (isOffloadedOrDirect()) { return NS_INACTIVE; } } @@ -1756,7 +1780,7 @@ nsecs_t AudioTrack::processAudioBuffer() status_t AudioTrack::restoreTrack_l(const char *from) { ALOGW("dead IAudioTrack, %s, creating a new one from %s()", - isOffloaded_l() ? "Offloaded" : "PCM", from); + isOffloadedOrDirect_l() ? "Offloaded or Direct" : "PCM", from); ++mSequence; status_t result; @@ -1764,7 +1788,7 @@ status_t AudioTrack::restoreTrack_l(const char *from) // output parameters in createTrack_l() AudioSystem::clearAudioConfigCache(); - if (isOffloaded_l()) { + if (isOffloadedOrDirect_l()) { // FIXME re-creation of offloaded tracks is not yet implemented return DEAD_OBJECT; } @@ -1850,6 +1874,19 @@ bool AudioTrack::isOffloaded() const return isOffloaded_l(); } +bool AudioTrack::isDirect() const +{ + AutoMutex lock(mLock); + return isDirect_l(); +} + +bool AudioTrack::isOffloadedOrDirect() const +{ + AutoMutex lock(mLock); + return isOffloadedOrDirect_l(); +} + + status_t AudioTrack::dump(int fd, const Vector& args __unused) const { diff --git a/services/audioflinger/PlaybackTracks.h b/services/audioflinger/PlaybackTracks.h index 6130084b6b..79bdfe8a44 100644 --- a/services/audioflinger/PlaybackTracks.h +++ b/services/audioflinger/PlaybackTracks.h @@ -54,6 +54,7 @@ public: return mStreamType; } bool isOffloaded() const { return (mFlags & IAudioFlinger::TRACK_OFFLOAD) != 0; } + bool isDirect() const { return (mFlags & IAudioFlinger::TRACK_DIRECT) != 0; } status_t setParameters(const String8& keyValuePairs); status_t attachAuxEffect(int EffectId); void setAuxBuffer(int EffectId, int32_t *buffer); diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp index d6390b1581..8ce819cdc2 100755 --- a/services/audioflinger/Threads.cpp +++ b/services/audioflinger/Threads.cpp @@ -1660,7 +1660,7 @@ bool AudioFlinger::PlaybackThread::destroyTrack_l(const sp& track) track->mState = TrackBase::STOPPED; if (!trackActive) { removeTrack_l(track); - } else if (track->isFastTrack() || track->isOffloaded()) { + } else if (track->isFastTrack() || track->isOffloaded() || track->isDirect()) { track->mState = TrackBase::STOPPING_1; } @@ -1868,7 +1868,9 @@ void AudioFlinger::PlaybackThread::readOutputParameters_l() } mNormalFrameCount = multiplier * mFrameCount; // round up to nearest 16 frames to satisfy AudioMixer - mNormalFrameCount = (mNormalFrameCount + 15) & ~15; + if (mType == MIXER || mType == DUPLICATING) { + mNormalFrameCount = (mNormalFrameCount + 15) & ~15; + } ALOGI("HAL output buffer size %u frames, normal sink buffer size %u frames", mFrameCount, mNormalFrameCount); @@ -2656,7 +2658,7 @@ status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp) if (mNormalSink != 0) { return mNormalSink->getTimestamp(timestamp); } - if (mType == OFFLOAD && mOutput->stream->get_presentation_position) { + if ((mType == OFFLOAD || mType == DIRECT) && mOutput->stream->get_presentation_position) { uint64_t position64; int ret = mOutput->stream->get_presentation_position( mOutput->stream, &position64, ×tamp.mTime); @@ -3947,14 +3949,16 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep // The first time a track is added we wait // for all its buffers to be filled before processing it uint32_t minFrames; - if ((track->sharedBuffer() == 0) && !track->isStopped() && !track->isPausing()) { + if ((track->sharedBuffer() == 0) && !track->isStopping_1() && !track->isPausing()) { minFrames = mNormalFrameCount; } else { minFrames = 1; } - if ((track->framesReady() >= minFrames) && track->isReady() && - !track->isPaused() && !track->isTerminated()) + ALOGI("prepareTracks_l minFrames %d state %d frames ready %d, ", + minFrames, track->mState, track->framesReady()); + if ((track->framesReady() >= minFrames) && track->isReady() && !track->isPaused() && + !track->isStopping_2() && !track->isStopped()) { ALOGVV("track %d s=%08x [OK]", track->name(), cblk->mServer); @@ -3981,17 +3985,26 @@ AudioFlinger::PlaybackThread::mixer_state AudioFlinger::DirectOutputThread::prep if (!mEffectChains.isEmpty() && last) { mEffectChains[0]->clearInputBuffer(); } - - ALOGVV("track %d s=%08x [NOT READY]", track->name(), cblk->mServer); - if ((track->sharedBuffer() != 0) || track->isTerminated() || - track->isStopped() || track->isPaused()) { + if (track->isStopping_1()) { + track->mState = TrackBase::STOPPING_2; + } + if ((track->sharedBuffer() != 0) || track->isStopped() || + track->isStopping_2() || track->isPaused()) { // We have consumed all the buffers of this track. // Remove it from the list of active tracks. - // TODO: implement behavior for compressed audio - size_t audioHALFrames = (latency_l() * mSampleRate) / 1000; + size_t audioHALFrames; + if (audio_is_linear_pcm(mFormat)) { + audioHALFrames = (latency_l() * mSampleRate) / 1000; + } else { + audioHALFrames = 0; + } + size_t framesWritten = mBytesWritten / mFrameSize; if (mStandby || !last || track->presentationComplete(framesWritten, audioHALFrames)) { + if (track->isStopping_2()) { + track->mState = TrackBase::STOPPED; + } if (track->isStopped()) { track->reset(); } diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp index 1e906adbdb..4fbb973341 100644 --- a/services/audioflinger/Tracks.cpp +++ b/services/audioflinger/Tracks.cpp @@ -706,7 +706,7 @@ void AudioFlinger::PlaybackThread::Track::stop() if (playbackThread->mActiveTracks.indexOf(this) < 0) { reset(); mState = STOPPED; - } else if (!isFastTrack() && !isOffloaded()) { + } else if (!isFastTrack() && !isOffloaded() && !isDirect()) { mState = STOPPED; } else { // For fast tracks prepareTracks_l() will set state to STOPPING_2 @@ -860,7 +860,7 @@ status_t AudioFlinger::PlaybackThread::Track::getTimestamp(AudioTimestamp& times } Mutex::Autolock _l(thread->mLock); PlaybackThread *playbackThread = (PlaybackThread *)thread.get(); - if (!isOffloaded()) { + if (!isOffloaded() && !isDirect()) { if (!playbackThread->mLatchQValid) { mPreviousValid = false; return INVALID_OPERATION; @@ -980,8 +980,6 @@ bool AudioFlinger::PlaybackThread::Track::presentationComplete(size_t framesWrit } if (framesWritten >= mPresentationCompleteFrames || isOffloaded()) { - ALOGV("presentationComplete() session %d complete: framesWritten %d", - mSessionId, framesWritten); triggerEvents(AudioSystem::SYNC_EVENT_PRESENTATION_COMPLETE); mAudioTrackServerProxy->setStreamEndDone(); return true; diff --git a/services/audiopolicy/AudioPolicyManager.cpp b/services/audiopolicy/AudioPolicyManager.cpp index 70dcb4c113..aa810bc706 100644 --- a/services/audiopolicy/AudioPolicyManager.cpp +++ b/services/audiopolicy/AudioPolicyManager.cpp @@ -122,6 +122,11 @@ const StringToEnum sFormatNameToEnumTable[] = { STRING_TO_ENUM(AUDIO_FORMAT_MP3), STRING_TO_ENUM(AUDIO_FORMAT_AAC), STRING_TO_ENUM(AUDIO_FORMAT_VORBIS), + STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V1), + STRING_TO_ENUM(AUDIO_FORMAT_HE_AAC_V2), + STRING_TO_ENUM(AUDIO_FORMAT_OPUS), + STRING_TO_ENUM(AUDIO_FORMAT_AC3), + STRING_TO_ENUM(AUDIO_FORMAT_E_AC3), }; const StringToEnum sOutChannelsNameToEnumTable[] = { -- 2.11.0