SoftAAC2.cpp revision 7c5abbb0e1b20df4b265a08a8560899f637f9b44
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#define LOG_TAG "SoftAAC2"
18//#define LOG_NDEBUG 0
19#include <utils/Log.h>
20
21#include "SoftAAC2.h"
22
23#include <cutils/properties.h>
24#include <media/stagefright/foundation/ADebug.h>
25#include <media/stagefright/foundation/hexdump.h>
26#include <media/stagefright/MediaErrors.h>
27
28#define FILEREAD_MAX_LAYERS 2
29
30#define DRC_DEFAULT_MOBILE_REF_LEVEL 64  /* 64*-0.25dB = -16 dB below full scale for mobile conf */
31#define DRC_DEFAULT_MOBILE_DRC_CUT   127 /* maximum compression of dynamic range for mobile conf */
32#define MAX_CHANNEL_COUNT            6  /* maximum number of audio channels that can be decoded */
33// names of properties that can be used to override the default DRC settings
34#define PROP_DRC_OVERRIDE_REF_LEVEL  "aac_drc_reference_level"
35#define PROP_DRC_OVERRIDE_CUT        "aac_drc_cut"
36#define PROP_DRC_OVERRIDE_BOOST      "aac_drc_boost"
37
38namespace android {
39
40template<class T>
41static void InitOMXParams(T *params) {
42    params->nSize = sizeof(T);
43    params->nVersion.s.nVersionMajor = 1;
44    params->nVersion.s.nVersionMinor = 0;
45    params->nVersion.s.nRevision = 0;
46    params->nVersion.s.nStep = 0;
47}
48
49SoftAAC2::SoftAAC2(
50        const char *name,
51        const OMX_CALLBACKTYPE *callbacks,
52        OMX_PTR appData,
53        OMX_COMPONENTTYPE **component)
54    : SimpleSoftOMXComponent(name, callbacks, appData, component),
55      mAACDecoder(NULL),
56      mStreamInfo(NULL),
57      mIsADTS(false),
58      mInputBufferCount(0),
59      mSignalledError(false),
60      mAnchorTimeUs(0),
61      mNumSamplesOutput(0),
62      mOutputPortSettingsChange(NONE) {
63    initPorts();
64    CHECK_EQ(initDecoder(), (status_t)OK);
65}
66
67SoftAAC2::~SoftAAC2() {
68    aacDecoder_Close(mAACDecoder);
69}
70
71void SoftAAC2::initPorts() {
72    OMX_PARAM_PORTDEFINITIONTYPE def;
73    InitOMXParams(&def);
74
75    def.nPortIndex = 0;
76    def.eDir = OMX_DirInput;
77    def.nBufferCountMin = kNumInputBuffers;
78    def.nBufferCountActual = def.nBufferCountMin;
79    def.nBufferSize = 8192;
80    def.bEnabled = OMX_TRUE;
81    def.bPopulated = OMX_FALSE;
82    def.eDomain = OMX_PortDomainAudio;
83    def.bBuffersContiguous = OMX_FALSE;
84    def.nBufferAlignment = 1;
85
86    def.format.audio.cMIMEType = const_cast<char *>("audio/aac");
87    def.format.audio.pNativeRender = NULL;
88    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
89    def.format.audio.eEncoding = OMX_AUDIO_CodingAAC;
90
91    addPort(def);
92
93    def.nPortIndex = 1;
94    def.eDir = OMX_DirOutput;
95    def.nBufferCountMin = kNumOutputBuffers;
96    def.nBufferCountActual = def.nBufferCountMin;
97    def.nBufferSize = 4096 * MAX_CHANNEL_COUNT;
98    def.bEnabled = OMX_TRUE;
99    def.bPopulated = OMX_FALSE;
100    def.eDomain = OMX_PortDomainAudio;
101    def.bBuffersContiguous = OMX_FALSE;
102    def.nBufferAlignment = 2;
103
104    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
105    def.format.audio.pNativeRender = NULL;
106    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
107    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
108
109    addPort(def);
110}
111
112status_t SoftAAC2::initDecoder() {
113    status_t status = UNKNOWN_ERROR;
114    mAACDecoder = aacDecoder_Open(TT_MP4_ADIF, /* num layers */ 1);
115    if (mAACDecoder != NULL) {
116        mStreamInfo = aacDecoder_GetStreamInfo(mAACDecoder);
117        if (mStreamInfo != NULL) {
118            status = OK;
119        }
120    }
121    mDecoderHasData = false;
122
123    // for streams that contain metadata, use the mobile profile DRC settings unless overridden
124    // by platform properties:
125    char value[PROPERTY_VALUE_MAX];
126    //  * AAC_DRC_REFERENCE_LEVEL
127    if (property_get(PROP_DRC_OVERRIDE_REF_LEVEL, value, NULL)) {
128        unsigned refLevel = atoi(value);
129        ALOGV("AAC decoder using AAC_DRC_REFERENCE_LEVEL of %d instead of %d",
130                refLevel, DRC_DEFAULT_MOBILE_REF_LEVEL);
131        aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, refLevel);
132    } else {
133        aacDecoder_SetParam(mAACDecoder, AAC_DRC_REFERENCE_LEVEL, DRC_DEFAULT_MOBILE_REF_LEVEL);
134    }
135    //  * AAC_DRC_ATTENUATION_FACTOR
136    if (property_get(PROP_DRC_OVERRIDE_CUT, value, NULL)) {
137        unsigned cut = atoi(value);
138        ALOGV("AAC decoder using AAC_DRC_ATTENUATION_FACTOR of %d instead of %d",
139                        cut, DRC_DEFAULT_MOBILE_DRC_CUT);
140        aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, cut);
141    } else {
142        aacDecoder_SetParam(mAACDecoder, AAC_DRC_ATTENUATION_FACTOR, DRC_DEFAULT_MOBILE_DRC_CUT);
143    }
144    //  * AAC_DRC_BOOST_FACTOR (note: no default, using cut)
145    if (property_get(PROP_DRC_OVERRIDE_BOOST, value, NULL)) {
146        unsigned boost = atoi(value);
147        ALOGV("AAC decoder using AAC_DRC_BOOST_FACTOR of %d", boost);
148        aacDecoder_SetParam(mAACDecoder, AAC_DRC_BOOST_FACTOR, boost);
149    }
150
151    return status;
152}
153
154OMX_ERRORTYPE SoftAAC2::internalGetParameter(
155        OMX_INDEXTYPE index, OMX_PTR params) {
156    switch (index) {
157        case OMX_IndexParamAudioAac:
158        {
159            OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
160                (OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
161
162            if (aacParams->nPortIndex != 0) {
163                return OMX_ErrorUndefined;
164            }
165
166            aacParams->nBitRate = 0;
167            aacParams->nAudioBandWidth = 0;
168            aacParams->nAACtools = 0;
169            aacParams->nAACERtools = 0;
170            aacParams->eAACProfile = OMX_AUDIO_AACObjectMain;
171
172            aacParams->eAACStreamFormat =
173                mIsADTS
174                    ? OMX_AUDIO_AACStreamFormatMP4ADTS
175                    : OMX_AUDIO_AACStreamFormatMP4FF;
176
177            aacParams->eChannelMode = OMX_AUDIO_ChannelModeStereo;
178
179            if (!isConfigured()) {
180                aacParams->nChannels = 1;
181                aacParams->nSampleRate = 44100;
182                aacParams->nFrameLength = 0;
183            } else {
184                aacParams->nChannels = mStreamInfo->numChannels;
185                aacParams->nSampleRate = mStreamInfo->sampleRate;
186                aacParams->nFrameLength = mStreamInfo->frameSize;
187            }
188
189            return OMX_ErrorNone;
190        }
191
192        case OMX_IndexParamAudioPcm:
193        {
194            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
195                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
196
197            if (pcmParams->nPortIndex != 1) {
198                return OMX_ErrorUndefined;
199            }
200
201            pcmParams->eNumData = OMX_NumericalDataSigned;
202            pcmParams->eEndian = OMX_EndianBig;
203            pcmParams->bInterleaved = OMX_TRUE;
204            pcmParams->nBitPerSample = 16;
205            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
206            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
207            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
208            pcmParams->eChannelMapping[2] = OMX_AUDIO_ChannelCF;
209            pcmParams->eChannelMapping[3] = OMX_AUDIO_ChannelLFE;
210            pcmParams->eChannelMapping[4] = OMX_AUDIO_ChannelLS;
211            pcmParams->eChannelMapping[5] = OMX_AUDIO_ChannelRS;
212
213            if (!isConfigured()) {
214                pcmParams->nChannels = 1;
215                pcmParams->nSamplingRate = 44100;
216            } else {
217                pcmParams->nChannels = mStreamInfo->numChannels;
218                pcmParams->nSamplingRate = mStreamInfo->sampleRate;
219            }
220
221            return OMX_ErrorNone;
222        }
223
224        default:
225            return SimpleSoftOMXComponent::internalGetParameter(index, params);
226    }
227}
228
229OMX_ERRORTYPE SoftAAC2::internalSetParameter(
230        OMX_INDEXTYPE index, const OMX_PTR params) {
231    switch (index) {
232        case OMX_IndexParamStandardComponentRole:
233        {
234            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
235                (const OMX_PARAM_COMPONENTROLETYPE *)params;
236
237            if (strncmp((const char *)roleParams->cRole,
238                        "audio_decoder.aac",
239                        OMX_MAX_STRINGNAME_SIZE - 1)) {
240                return OMX_ErrorUndefined;
241            }
242
243            return OMX_ErrorNone;
244        }
245
246        case OMX_IndexParamAudioAac:
247        {
248            const OMX_AUDIO_PARAM_AACPROFILETYPE *aacParams =
249                (const OMX_AUDIO_PARAM_AACPROFILETYPE *)params;
250
251            if (aacParams->nPortIndex != 0) {
252                return OMX_ErrorUndefined;
253            }
254
255            if (aacParams->eAACStreamFormat == OMX_AUDIO_AACStreamFormatMP4FF) {
256                mIsADTS = false;
257            } else if (aacParams->eAACStreamFormat
258                        == OMX_AUDIO_AACStreamFormatMP4ADTS) {
259                mIsADTS = true;
260            } else {
261                return OMX_ErrorUndefined;
262            }
263
264            return OMX_ErrorNone;
265        }
266
267        case OMX_IndexParamAudioPcm:
268        {
269            const OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
270                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
271
272            if (pcmParams->nPortIndex != 1) {
273                return OMX_ErrorUndefined;
274            }
275
276            return OMX_ErrorNone;
277        }
278
279        default:
280            return SimpleSoftOMXComponent::internalSetParameter(index, params);
281    }
282}
283
284bool SoftAAC2::isConfigured() const {
285    return mInputBufferCount > 0;
286}
287
288void SoftAAC2::maybeConfigureDownmix() const {
289    if (mStreamInfo->numChannels > 2) {
290        char value[PROPERTY_VALUE_MAX];
291        if (!(property_get("media.aac_51_output_enabled", value, NULL) &&
292                (!strcmp(value, "1") || !strcasecmp(value, "true")))) {
293            ALOGI("Downmixing multichannel AAC to stereo");
294            aacDecoder_SetParam(mAACDecoder, AAC_PCM_OUTPUT_CHANNELS, 2);
295            mStreamInfo->numChannels = 2;
296        }
297    }
298}
299
300void SoftAAC2::onQueueFilled(OMX_U32 portIndex) {
301    if (mSignalledError || mOutputPortSettingsChange != NONE) {
302        return;
303    }
304
305    UCHAR* inBuffer[FILEREAD_MAX_LAYERS];
306    UINT inBufferLength[FILEREAD_MAX_LAYERS] = {0};
307    UINT bytesValid[FILEREAD_MAX_LAYERS] = {0};
308
309    List<BufferInfo *> &inQueue = getPortQueue(0);
310    List<BufferInfo *> &outQueue = getPortQueue(1);
311
312    if (portIndex == 0 && mInputBufferCount == 0) {
313        ++mInputBufferCount;
314        BufferInfo *info = *inQueue.begin();
315        OMX_BUFFERHEADERTYPE *header = info->mHeader;
316
317        inBuffer[0] = header->pBuffer + header->nOffset;
318        inBufferLength[0] = header->nFilledLen;
319
320        AAC_DECODER_ERROR decoderErr =
321            aacDecoder_ConfigRaw(mAACDecoder,
322                                 inBuffer,
323                                 inBufferLength);
324
325        if (decoderErr != AAC_DEC_OK) {
326            mSignalledError = true;
327            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
328            return;
329        }
330
331        inQueue.erase(inQueue.begin());
332        info->mOwnedByUs = false;
333        notifyEmptyBufferDone(header);
334
335        // Only send out port settings changed event if both sample rate
336        // and numChannels are valid.
337        if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
338            maybeConfigureDownmix();
339            ALOGI("Initially configuring decoder: %d Hz, %d channels",
340                mStreamInfo->sampleRate,
341                mStreamInfo->numChannels);
342
343            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
344            mOutputPortSettingsChange = AWAITING_DISABLED;
345        }
346
347        return;
348    }
349
350    while (!inQueue.empty() && !outQueue.empty()) {
351        BufferInfo *inInfo = *inQueue.begin();
352        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
353
354        BufferInfo *outInfo = *outQueue.begin();
355        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
356
357        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
358            inQueue.erase(inQueue.begin());
359            inInfo->mOwnedByUs = false;
360            notifyEmptyBufferDone(inHeader);
361
362            if (mDecoderHasData) {
363                // flush out the decoder's delayed data by calling DecodeFrame
364                // one more time, with the AACDEC_FLUSH flag set
365                INT_PCM *outBuffer =
366                        reinterpret_cast<INT_PCM *>(
367                                outHeader->pBuffer + outHeader->nOffset);
368
369                AAC_DECODER_ERROR decoderErr =
370                    aacDecoder_DecodeFrame(mAACDecoder,
371                                           outBuffer,
372                                           outHeader->nAllocLen,
373                                           AACDEC_FLUSH);
374                mDecoderHasData = false;
375
376                if (decoderErr != AAC_DEC_OK) {
377                    mSignalledError = true;
378
379                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
380                           NULL);
381
382                    return;
383                }
384
385                outHeader->nFilledLen =
386                        mStreamInfo->frameSize
387                            * sizeof(int16_t)
388                            * mStreamInfo->numChannels;
389            } else {
390                // we never submitted any data to the decoder, so there's nothing to flush out
391                outHeader->nFilledLen = 0;
392            }
393
394            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
395
396            outQueue.erase(outQueue.begin());
397            outInfo->mOwnedByUs = false;
398            notifyFillBufferDone(outHeader);
399            return;
400        }
401
402        if (inHeader->nOffset == 0) {
403            mAnchorTimeUs = inHeader->nTimeStamp;
404            mNumSamplesOutput = 0;
405        }
406
407        size_t adtsHeaderSize = 0;
408        if (mIsADTS) {
409            // skip 30 bits, aac_frame_length follows.
410            // ssssssss ssssiiip ppffffPc ccohCCll llllllll lll?????
411
412            const uint8_t *adtsHeader = inHeader->pBuffer + inHeader->nOffset;
413
414            bool signalError = false;
415            if (inHeader->nFilledLen < 7) {
416                ALOGE("Audio data too short to contain even the ADTS header. "
417                      "Got %ld bytes.", inHeader->nFilledLen);
418                hexdump(adtsHeader, inHeader->nFilledLen);
419                signalError = true;
420            } else {
421                bool protectionAbsent = (adtsHeader[1] & 1);
422
423                unsigned aac_frame_length =
424                    ((adtsHeader[3] & 3) << 11)
425                    | (adtsHeader[4] << 3)
426                    | (adtsHeader[5] >> 5);
427
428                if (inHeader->nFilledLen < aac_frame_length) {
429                    ALOGE("Not enough audio data for the complete frame. "
430                          "Got %ld bytes, frame size according to the ADTS "
431                          "header is %u bytes.",
432                          inHeader->nFilledLen, aac_frame_length);
433                    hexdump(adtsHeader, inHeader->nFilledLen);
434                    signalError = true;
435                } else {
436                    adtsHeaderSize = (protectionAbsent ? 7 : 9);
437
438                    inBuffer[0] = (UCHAR *)adtsHeader + adtsHeaderSize;
439                    inBufferLength[0] = aac_frame_length - adtsHeaderSize;
440
441                    inHeader->nOffset += adtsHeaderSize;
442                    inHeader->nFilledLen -= adtsHeaderSize;
443                }
444            }
445
446            if (signalError) {
447                mSignalledError = true;
448
449                notify(OMX_EventError,
450                       OMX_ErrorStreamCorrupt,
451                       ERROR_MALFORMED,
452                       NULL);
453
454                return;
455            }
456        } else {
457            inBuffer[0] = inHeader->pBuffer + inHeader->nOffset;
458            inBufferLength[0] = inHeader->nFilledLen;
459        }
460
461        // Fill and decode
462        INT_PCM *outBuffer = reinterpret_cast<INT_PCM *>(
463                outHeader->pBuffer + outHeader->nOffset);
464
465        bytesValid[0] = inBufferLength[0];
466
467        int prevSampleRate = mStreamInfo->sampleRate;
468        int prevNumChannels = mStreamInfo->numChannels;
469
470        AAC_DECODER_ERROR decoderErr = AAC_DEC_NOT_ENOUGH_BITS;
471        while (bytesValid[0] > 0 && decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
472            aacDecoder_Fill(mAACDecoder,
473                            inBuffer,
474                            inBufferLength,
475                            bytesValid);
476            mDecoderHasData = true;
477
478            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
479                                                outBuffer,
480                                                outHeader->nAllocLen,
481                                                0 /* flags */);
482
483            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
484                ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
485            }
486        }
487
488        size_t numOutBytes =
489            mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
490
491        if (decoderErr == AAC_DEC_OK) {
492            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
493            inHeader->nFilledLen -= inBufferUsedLength;
494            inHeader->nOffset += inBufferUsedLength;
495        } else {
496            ALOGW("AAC decoder returned error %d, substituting silence",
497                  decoderErr);
498
499            memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
500
501            // Discard input buffer.
502            inHeader->nFilledLen = 0;
503
504            aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
505
506            // fall through
507        }
508
509        if (inHeader->nFilledLen == 0) {
510            inInfo->mOwnedByUs = false;
511            inQueue.erase(inQueue.begin());
512            inInfo = NULL;
513            notifyEmptyBufferDone(inHeader);
514            inHeader = NULL;
515        }
516
517        /*
518         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
519         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
520         * rate system and the sampling rate in the final output is actually
521         * doubled compared with the core AAC decoder sampling rate.
522         *
523         * Explicit signalling is done by explicitly defining SBR audio object
524         * type in the bitstream. Implicit signalling is done by embedding
525         * SBR content in AAC extension payload specific to SBR, and hence
526         * requires an AAC decoder to perform pre-checks on actual audio frames.
527         *
528         * Thus, we could not say for sure whether a stream is
529         * AAC+/eAAC+ until the first data frame is decoded.
530         */
531        if (mInputBufferCount <= 2) {
532            if (mStreamInfo->sampleRate != prevSampleRate ||
533                mStreamInfo->numChannels != prevNumChannels) {
534                maybeConfigureDownmix();
535                ALOGI("Reconfiguring decoder: %d->%d Hz, %d->%d channels",
536                      prevSampleRate, mStreamInfo->sampleRate,
537                      prevNumChannels, mStreamInfo->numChannels);
538
539                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
540                mOutputPortSettingsChange = AWAITING_DISABLED;
541                return;
542            }
543        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
544            ALOGW("Invalid AAC stream");
545            mSignalledError = true;
546            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
547            return;
548        }
549
550        if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) {
551            // We'll only output data if we successfully decoded it or
552            // we've previously decoded valid data, in the latter case
553            // (decode failed) we'll output a silent frame.
554            outHeader->nFilledLen = numOutBytes;
555            outHeader->nFlags = 0;
556
557            outHeader->nTimeStamp =
558                mAnchorTimeUs
559                    + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate;
560
561            mNumSamplesOutput += mStreamInfo->frameSize;
562
563            outInfo->mOwnedByUs = false;
564            outQueue.erase(outQueue.begin());
565            outInfo = NULL;
566            notifyFillBufferDone(outHeader);
567            outHeader = NULL;
568        }
569
570        if (decoderErr == AAC_DEC_OK) {
571            ++mInputBufferCount;
572        }
573    }
574}
575
576void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) {
577    if (portIndex == 0) {
578        // Make sure that the next buffer output does not still
579        // depend on fragments from the last one decoded.
580        // drain all existing data
581        drainDecoder();
582    }
583}
584
585void SoftAAC2::drainDecoder() {
586    short buf [2048];
587    aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
588    aacDecoder_DecodeFrame(mAACDecoder, buf, 4096, AACDEC_FLUSH | AACDEC_CLRHIST | AACDEC_INTR);
589    aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
590    mDecoderHasData = false;
591}
592
593void SoftAAC2::onReset() {
594    drainDecoder();
595    // reset the "configured" state
596    mInputBufferCount = 0;
597    mNumSamplesOutput = 0;
598    // To make the codec behave the same before and after a reset, we need to invalidate the
599    // streaminfo struct. This does that:
600    mStreamInfo->sampleRate = 0;
601}
602
603void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
604    if (portIndex != 1) {
605        return;
606    }
607
608    switch (mOutputPortSettingsChange) {
609        case NONE:
610            break;
611
612        case AWAITING_DISABLED:
613        {
614            CHECK(!enabled);
615            mOutputPortSettingsChange = AWAITING_ENABLED;
616            break;
617        }
618
619        default:
620        {
621            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
622            CHECK(enabled);
623            mOutputPortSettingsChange = NONE;
624            break;
625        }
626    }
627}
628
629}  // namespace android
630
631android::SoftOMXComponent *createSoftOMXComponent(
632        const char *name, const OMX_CALLBACKTYPE *callbacks,
633        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
634    return new android::SoftAAC2(name, callbacks, appData, component);
635}
636