OSDN Git Service

AudioTrack: add support for compressed audio
authorEric Laurent <elaurent@google.com>
Tue, 10 Jun 2014 00:22:27 +0000 (17:22 -0700)
committerEric Laurent <elaurent@google.com>
Thu, 19 Jun 2014 17:05:57 +0000 (10:05 -0700)
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
include/media/IAudioFlinger.h
media/libmedia/AudioTrack.cpp
services/audioflinger/PlaybackTracks.h
services/audioflinger/Threads.cpp
services/audioflinger/Tracks.cpp
services/audiopolicy/AudioPolicyManager.cpp

index 5dc77a3..3492520 100644 (file)
@@ -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<IAudioTrack>         mAudioTrack;
     sp<IMemory>             mCblkMemory;
index c742810..fc8be20 100644 (file)
@@ -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;
 
index 77419f0..5c82cfb 100644 (file)
@@ -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<IAudioTrack> 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<String16>& args __unused) const
 {
 
index 6130084..79bdfe8 100644 (file)
@@ -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);
index d6390b1..8ce819c 100755 (executable)
@@ -1660,7 +1660,7 @@ bool AudioFlinger::PlaybackThread::destroyTrack_l(const sp<Track>& 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, &timestamp.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();
                     }
index 1e906ad..4fbb973 100644 (file)
@@ -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;
index 70dcb4c..aa810bc 100644 (file)
@@ -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[] = {