Added support for HE-AAC recording

Fixed bug in decoder related to sample rates / channel counts
Made decoder follow Fraunhofer pattern
Log if bitrate not available
Bug: 6275957

Change-Id: I47a8e29358fa4a88ebc73fe02d46a2bfb96c64fe
diff --git a/media/libmedia/MediaProfiles.cpp b/media/libmedia/MediaProfiles.cpp
index c08f033..6929efa 100644
--- a/media/libmedia/MediaProfiles.cpp
+++ b/media/libmedia/MediaProfiles.cpp
@@ -44,7 +44,8 @@
     {"amrnb",  AUDIO_ENCODER_AMR_NB},
     {"amrwb",  AUDIO_ENCODER_AMR_WB},
     {"aac",    AUDIO_ENCODER_AAC},
-    {"aaceld", AUDIO_ENCODER_AAC_ELD},
+    {"heaac",  AUDIO_ENCODER_HE_AAC},
+    {"aaceld", AUDIO_ENCODER_AAC_ELD}
 };
 
 const MediaProfiles::NameToTagMap MediaProfiles::sFileFormatMap[] = {
diff --git a/media/libmediaplayerservice/StagefrightRecorder.cpp b/media/libmediaplayerservice/StagefrightRecorder.cpp
index b676cc7..727fd0d 100644
--- a/media/libmediaplayerservice/StagefrightRecorder.cpp
+++ b/media/libmediaplayerservice/StagefrightRecorder.cpp
@@ -820,10 +820,15 @@
             mime = MEDIA_MIMETYPE_AUDIO_AAC;
             encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectLC);
             break;
+        case AUDIO_ENCODER_HE_AAC:
+            mime = MEDIA_MIMETYPE_AUDIO_AAC;
+            encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectHE);
+            break;
         case AUDIO_ENCODER_AAC_ELD:
             mime = MEDIA_MIMETYPE_AUDIO_AAC;
             encMeta->setInt32(kKeyAACProfile, OMX_AUDIO_AACObjectELD);
             break;
+
         default:
             ALOGE("Unknown audio encoder: %d", mAudioEncoder);
             return NULL;
@@ -844,7 +849,6 @@
 
     OMXClient client;
     CHECK_EQ(client.connect(), (status_t)OK);
-
     sp<MediaSource> audioEncoder =
         OMXCodec::Create(client.interface(), encMeta,
                          true /* createEncoder */, audioSource);
@@ -859,6 +863,7 @@
     CHECK_EQ(mOutputFormat, OUTPUT_FORMAT_AAC_ADTS);
 
     CHECK(mAudioEncoder == AUDIO_ENCODER_AAC ||
+          mAudioEncoder == AUDIO_ENCODER_HE_AAC ||
           mAudioEncoder == AUDIO_ENCODER_AAC_ELD);
     CHECK(mAudioSource != AUDIO_SOURCE_CNT);
 
@@ -977,7 +982,9 @@
     sp<MediaWriter> writer = new MPEG2TSWriter(mOutputFd);
 
     if (mAudioSource != AUDIO_SOURCE_CNT) {
-        if (mAudioEncoder != AUDIO_ENCODER_AAC) {
+        if (mAudioEncoder != AUDIO_ENCODER_AAC &&
+            mAudioEncoder != AUDIO_ENCODER_HE_AAC &&
+            mAudioEncoder != AUDIO_ENCODER_AAC_ELD) {
             return ERROR_UNSUPPORTED;
         }
 
@@ -1442,6 +1449,7 @@
         case AUDIO_ENCODER_AMR_NB:
         case AUDIO_ENCODER_AMR_WB:
         case AUDIO_ENCODER_AAC:
+        case AUDIO_ENCODER_HE_AAC:
         case AUDIO_ENCODER_AAC_ELD:
             break;
 
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index 547a554..bf7befd 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -142,9 +142,9 @@
                 aacParams->nSampleRate = 44100;
                 aacParams->nFrameLength = 0;
             } else {
-                aacParams->nChannels = mStreamInfo->channelConfig;
-                aacParams->nSampleRate = mStreamInfo->aacSampleRate;
-                aacParams->nFrameLength = mStreamInfo->aacSamplesPerFrame;
+                aacParams->nChannels = mStreamInfo->numChannels;
+                aacParams->nSampleRate = mStreamInfo->sampleRate;
+                aacParams->nFrameLength = mStreamInfo->frameSize;
             }
 
             return OMX_ErrorNone;
@@ -175,7 +175,7 @@
                 pcmParams->nChannels = 1;
                 pcmParams->nSamplingRate = 44100;
             } else {
-                pcmParams->nChannels = mStreamInfo->channelConfig;
+                pcmParams->nChannels = mStreamInfo->numChannels;
                 pcmParams->nSamplingRate = mStreamInfo->sampleRate;
             }
 
@@ -185,6 +185,7 @@
         default:
             return SimpleSoftOMXComponent::internalGetParameter(index, params);
     }
+
 }
 
 OMX_ERRORTYPE SoftAAC2::internalSetParameter(
@@ -254,7 +255,6 @@
     UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
     UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
     UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};
-    AAC_DECODER_ERROR decoderErr;
 
     List<BufferInfo *> &inQueue = getPortQueue(0);
     List<BufferInfo *> &outQueue = getPortQueue(1);
@@ -277,7 +277,6 @@
             notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
             return;
         }
-
         inQueue.erase(inQueue.begin());
         info->mOwnedByUs = false;
         notifyEmptyBufferDone(header);
@@ -303,10 +302,16 @@
             // the AACDEC_FLUSH flag set
             INT_PCM *outBuffer =
                     reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
-            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                                outBuffer,
-                                                outHeader->nAllocLen,
-                                                AACDEC_FLUSH);
+            AAC_DECODER_ERROR decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+                                                                  outBuffer,
+                                                                  outHeader->nAllocLen,
+                                                                  AACDEC_FLUSH);
+            if (decoderErr != AAC_DEC_OK) {
+                mSignalledError = true;
+                notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
+                return;
+            }
+
             outHeader->nFilledLen =
                     mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
@@ -352,23 +357,27 @@
             inBufferLength[0] = inHeader->nFilledLen;
         }
 
-
         // Fill and decode
         INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(outHeader->pBuffer + outHeader->nOffset);
         bytesValid[0] = inBufferLength[0];
 
         int flags = mInputDiscontinuity ? AACDEC_INTR : 0;
         int prevSampleRate = mStreamInfo->sampleRate;
-        decoderErr = aacDecoder_Fill(mAACDecoder,
-                                     inBuffer,
-                                     inBufferLength,
-                                     bytesValid);
+        int prevNumChannels = mStreamInfo->numChannels;
 
-        decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
-                                            outBuffer,
-                                            outHeader->nAllocLen,
-                                            flags);
+        AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
+        while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
+            aacDecoder_Fill(mAACDecoder,
+                            inBuffer,
+                            inBufferLength,
+                            bytesValid);
 
+            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
+                                                outBuffer,
+                                                outHeader->nAllocLen,
+                                                flags);
+
+        }
         mInputDiscontinuity = false;
 
         /*
@@ -386,7 +395,8 @@
          * AAC+/eAAC+ until the first data frame is decoded.
          */
         if (mInputBufferCount <= 2) {
-            if (mStreamInfo->sampleRate != prevSampleRate) {
+            if (mStreamInfo->sampleRate != prevSampleRate ||
+                mStreamInfo->numChannels != prevNumChannels) {
                 // We're going to want to revisit this input buffer, but
                 // may have already advanced the offset. Undo that if
                 // necessary.
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 4947fb2..7719435 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -239,7 +239,6 @@
             mBitRate = aacParams->nBitRate;
             mNumChannels = aacParams->nChannels;
             mSampleRate = aacParams->nSampleRate;
-
             if (aacParams->eAACProfile != OMX_AUDIO_AACObjectNull) {
                 mAACProfile = aacParams->eAACProfile;
             }
@@ -262,7 +261,6 @@
 
             mNumChannels = pcmParams->nChannels;
             mSampleRate = pcmParams->nSamplingRate;
-
             if (setAudioParams() != OK) {
                 return OMX_ErrorUndefined;
             }
@@ -275,7 +273,7 @@
     }
 }
 
-CHANNEL_MODE getChannelMode(OMX_U32 nChannels) {
+static CHANNEL_MODE getChannelMode(OMX_U32 nChannels) {
     CHANNEL_MODE chMode = MODE_INVALID;
     switch (nChannels) {
         case 1: chMode = MODE_1; break;
@@ -289,6 +287,19 @@
     return chMode;
 }
 
+static AUDIO_OBJECT_TYPE getAOTFromProfile(OMX_U32 profile) {
+    if (profile == OMX_AUDIO_AACObjectLC) {
+        return AOT_AAC_LC;
+    } else if (profile == OMX_AUDIO_AACObjectHE) {
+        return AOT_SBR;
+    } else if (profile == OMX_AUDIO_AACObjectELD) {
+        return AOT_ER_AAC_ELD;
+    } else {
+        ALOGW("Unsupported AAC profile - defaulting to AAC-LC");
+        return AOT_AAC_LC;
+    }
+}
+
 status_t SoftAACEncoder2::setAudioParams() {
     // We call this whenever sample rate, number of channels or bitrate change
     // in reponse to setParameter calls.
@@ -297,7 +308,7 @@
          mSampleRate, mNumChannels, mBitRate);
 
     if (AACENC_OK != aacEncoder_SetParam(mAACEncoder, AACENC_AOT,
-            mAACProfile == OMX_AUDIO_AACObjectELD ? AOT_ER_AAC_ELD : AOT_AAC_LC)) {
+            getAOTFromProfile(mAACProfile))) {
         ALOGE("Failed to set AAC encoder parameters");
         return UNKNOWN_ERROR;
     }
@@ -341,12 +352,17 @@
         }
 
         if (AACENC_OK != aacEncEncode(mAACEncoder, NULL, NULL, NULL, NULL)) {
-            ALOGE("Failed to initialize AAC encoder");
+            ALOGE("Unable to initialize encoder for profile / sample-rate / bit-rate / channels");
             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
             mSignalledError = true;
             return;
         }
 
+        OMX_U32 actualBitRate  = aacEncoder_GetParam(mAACEncoder, AACENC_BITRATE);
+        if (mBitRate != actualBitRate) {
+            ALOGW("Requested bitrate %lu unsupported, using %lu", mBitRate, actualBitRate);
+        }
+
         AACENC_InfoStruct encInfo;
         if (AACENC_OK != aacEncInfo(mAACEncoder, &encInfo)) {
             ALOGE("Failed to get AAC encoder info");
@@ -373,7 +389,7 @@
     size_t numBytesPerInputFrame =
         mNumChannels * kNumSamplesPerFrame * sizeof(int16_t);
 
-    // BUGBUG: Fraunhofer's decoder chokes on large chunks of AAC-ELD
+    // Limit input size so we only get one ELD frame
     if (mAACProfile == OMX_AUDIO_AACObjectELD && numBytesPerInputFrame > 512) {
         numBytesPerInputFrame = 512;
     }
@@ -402,7 +418,7 @@
             }
 
             if (mInputFrame == NULL) {
-                mInputFrame = new int16_t[kNumSamplesPerFrame * mNumChannels];
+                mInputFrame = new int16_t[numBytesPerInputFrame / sizeof(int16_t)];
             }
 
             if (mInputSize == 0) {
@@ -490,6 +506,7 @@
         // Encode the mInputFrame, which is treated as a modulo buffer
         AACENC_ERROR encoderErr = AACENC_OK;
         size_t nOutputBytes = 0;
+
         do {
             memset(&outargs, 0, sizeof(outargs));