SoftAAC2.cpp revision 5a755c3856ca1f5b4c6b36810d51ca574947b8ae
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 48  /* 48*-0.25dB = -12 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    mIsFirst = true;
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        inQueue.erase(inQueue.begin());
331        info->mOwnedByUs = false;
332        notifyEmptyBufferDone(header);
333
334        // Only send out port settings changed event if both sample rate
335        // and numChannels are valid.
336        if (mStreamInfo->sampleRate && mStreamInfo->numChannels) {
337            maybeConfigureDownmix();
338            ALOGI("Initially configuring decoder: %d Hz, %d channels",
339                mStreamInfo->sampleRate,
340                mStreamInfo->numChannels);
341
342            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
343            mOutputPortSettingsChange = AWAITING_DISABLED;
344        }
345
346        return;
347    }
348
349    while (!inQueue.empty() && !outQueue.empty()) {
350        BufferInfo *inInfo = *inQueue.begin();
351        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
352
353        BufferInfo *outInfo = *outQueue.begin();
354        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
355
356        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
357            inQueue.erase(inQueue.begin());
358            inInfo->mOwnedByUs = false;
359            notifyEmptyBufferDone(inHeader);
360
361            if (!mIsFirst) {
362                // flush out the decoder's delayed data by calling DecodeFrame
363                // one more time, with the AACDEC_FLUSH flag set
364                INT_PCM *outBuffer =
365                        reinterpret_cast<INT_PCM *>(
366                                outHeader->pBuffer + outHeader->nOffset);
367
368                AAC_DECODER_ERROR decoderErr =
369                    aacDecoder_DecodeFrame(mAACDecoder,
370                                           outBuffer,
371                                           outHeader->nAllocLen,
372                                           AACDEC_FLUSH);
373
374                if (decoderErr != AAC_DEC_OK) {
375                    mSignalledError = true;
376
377                    notify(OMX_EventError, OMX_ErrorUndefined, decoderErr,
378                           NULL);
379
380                    return;
381                }
382
383                outHeader->nFilledLen =
384                        mStreamInfo->frameSize
385                            * sizeof(int16_t)
386                            * mStreamInfo->numChannels;
387            } else {
388                // Since we never discarded frames from the start, we won't have
389                // to add any padding at the end either.
390
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
477            decoderErr = aacDecoder_DecodeFrame(mAACDecoder,
478                                                outBuffer,
479                                                outHeader->nAllocLen,
480                                                0 /* flags */);
481
482            if (decoderErr == AAC_DEC_NOT_ENOUGH_BITS) {
483                ALOGW("Not enough bits, bytesValid %d", bytesValid[0]);
484            }
485        }
486
487        /*
488         * AAC+/eAAC+ streams can be signalled in two ways: either explicitly
489         * or implicitly, according to MPEG4 spec. AAC+/eAAC+ is a dual
490         * rate system and the sampling rate in the final output is actually
491         * doubled compared with the core AAC decoder sampling rate.
492         *
493         * Explicit signalling is done by explicitly defining SBR audio object
494         * type in the bitstream. Implicit signalling is done by embedding
495         * SBR content in AAC extension payload specific to SBR, and hence
496         * requires an AAC decoder to perform pre-checks on actual audio frames.
497         *
498         * Thus, we could not say for sure whether a stream is
499         * AAC+/eAAC+ until the first data frame is decoded.
500         */
501        if (mInputBufferCount <= 2) {
502            if (mStreamInfo->sampleRate != prevSampleRate ||
503                mStreamInfo->numChannels != prevNumChannels) {
504                maybeConfigureDownmix();
505                ALOGI("Reconfiguring decoder: %d Hz, %d channels",
506                      mStreamInfo->sampleRate,
507                      mStreamInfo->numChannels);
508
509                // We're going to want to revisit this input buffer, but
510                // may have already advanced the offset. Undo that if
511                // necessary.
512                inHeader->nOffset -= adtsHeaderSize;
513                inHeader->nFilledLen += adtsHeaderSize;
514
515                notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
516                mOutputPortSettingsChange = AWAITING_DISABLED;
517                return;
518            }
519        } else if (!mStreamInfo->sampleRate || !mStreamInfo->numChannels) {
520            ALOGW("Invalid AAC stream");
521            mSignalledError = true;
522            notify(OMX_EventError, OMX_ErrorUndefined, decoderErr, NULL);
523            return;
524        }
525
526        size_t numOutBytes =
527            mStreamInfo->frameSize * sizeof(int16_t) * mStreamInfo->numChannels;
528
529        if (decoderErr == AAC_DEC_OK) {
530            UINT inBufferUsedLength = inBufferLength[0] - bytesValid[0];
531            inHeader->nFilledLen -= inBufferUsedLength;
532            inHeader->nOffset += inBufferUsedLength;
533        } else {
534            ALOGW("AAC decoder returned error %d, substituting silence",
535                  decoderErr);
536
537            memset(outHeader->pBuffer + outHeader->nOffset, 0, numOutBytes);
538
539            // Discard input buffer.
540            inHeader->nFilledLen = 0;
541
542            aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
543
544            // fall through
545        }
546
547        if (decoderErr == AAC_DEC_OK || mNumSamplesOutput > 0) {
548            // We'll only output data if we successfully decoded it or
549            // we've previously decoded valid data, in the latter case
550            // (decode failed) we'll output a silent frame.
551            if (mIsFirst) {
552                mIsFirst = false;
553                // the first decoded frame should be discarded to account
554                // for decoder delay
555                numOutBytes = 0;
556            }
557
558            outHeader->nFilledLen = numOutBytes;
559            outHeader->nFlags = 0;
560
561            outHeader->nTimeStamp =
562                mAnchorTimeUs
563                    + (mNumSamplesOutput * 1000000ll) / mStreamInfo->sampleRate;
564
565            mNumSamplesOutput += mStreamInfo->frameSize;
566
567            outInfo->mOwnedByUs = false;
568            outQueue.erase(outQueue.begin());
569            outInfo = NULL;
570            notifyFillBufferDone(outHeader);
571            outHeader = NULL;
572        }
573
574        if (inHeader->nFilledLen == 0) {
575            inInfo->mOwnedByUs = false;
576            inQueue.erase(inQueue.begin());
577            inInfo = NULL;
578            notifyEmptyBufferDone(inHeader);
579            inHeader = NULL;
580        }
581
582        if (decoderErr == AAC_DEC_OK) {
583            ++mInputBufferCount;
584        }
585    }
586}
587
588void SoftAAC2::onPortFlushCompleted(OMX_U32 portIndex) {
589    if (portIndex == 0) {
590        // Make sure that the next buffer output does not still
591        // depend on fragments from the last one decoded.
592        aacDecoder_SetParam(mAACDecoder, AAC_TPDEC_CLEAR_BUFFER, 1);
593        mIsFirst = true;
594    }
595}
596
597void SoftAAC2::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
598    if (portIndex != 1) {
599        return;
600    }
601
602    switch (mOutputPortSettingsChange) {
603        case NONE:
604            break;
605
606        case AWAITING_DISABLED:
607        {
608            CHECK(!enabled);
609            mOutputPortSettingsChange = AWAITING_ENABLED;
610            break;
611        }
612
613        default:
614        {
615            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
616            CHECK(enabled);
617            mOutputPortSettingsChange = NONE;
618            break;
619        }
620    }
621}
622
623}  // namespace android
624
625android::SoftOMXComponent *createSoftOMXComponent(
626        const char *name, const OMX_CALLBACKTYPE *callbacks,
627        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
628    return new android::SoftAAC2(name, callbacks, appData, component);
629}
630