1bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian/*
2bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * Copyright (C) 2014 The Android Open Source Project
3bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian *
4bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * Licensed under the Apache License, Version 2.0 (the "License");
5bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * you may not use this file except in compliance with the License.
6bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * You may obtain a copy of the License at
7bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian *
8bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian *      http://www.apache.org/licenses/LICENSE-2.0
9bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian *
10bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * Unless required by applicable law or agreed to in writing, software
11bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * distributed under the License is distributed on an "AS IS" BASIS,
12bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * See the License for the specific language governing permissions and
14bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian * limitations under the License.
15bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian */
16bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
17bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian//#define LOG_NDEBUG 0
18bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian#define LOG_TAG "SoftOpus"
19bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian#include <utils/Log.h>
20bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
21bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian#include "SoftOpus.h"
2217d653523898c01816457743ab376a7b0427611fLajos Molnar#include <OMX_AudioExt.h>
2317d653523898c01816457743ab376a7b0427611fLajos Molnar#include <OMX_IndexExt.h>
24bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
25bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian#include <media/stagefright/foundation/ADebug.h>
26bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian#include <media/stagefright/MediaDefs.h>
27bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
28bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianextern "C" {
29bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    #include <opus.h>
30bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    #include <opus_multistream.h>
31bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
32bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
33bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramaniannamespace android {
34bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
35bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kRate = 48000;
36bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
37bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramaniantemplate<class T>
38bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic void InitOMXParams(T *params) {
39bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nSize = sizeof(T);
40bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nVersionMajor = 1;
41bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nVersionMinor = 0;
42bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nRevision = 0;
43bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nStep = 0;
44bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
45bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
46bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianSoftOpus::SoftOpus(
47bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const char *name,
48bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const OMX_CALLBACKTYPE *callbacks,
49bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_PTR appData,
50bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_COMPONENTTYPE **component)
51bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    : SimpleSoftOMXComponent(name, callbacks, appData, component),
52bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mInputBufferCount(0),
53bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mDecoder(NULL),
54bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mHeader(NULL),
55bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mCodecDelay(0),
56bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mSeekPreRoll(0),
57bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mAnchorTimeUs(0),
58bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mNumFramesOutput(0),
59bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mOutputPortSettingsChange(NONE) {
60bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    initPorts();
61bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    CHECK_EQ(initDecoder(), (status_t)OK);
62bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
63bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
64bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianSoftOpus::~SoftOpus() {
65bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mDecoder != NULL) {
66bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_destroy(mDecoder);
67bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mDecoder = NULL;
68bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
69bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mHeader != NULL) {
70bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        delete mHeader;
71bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mHeader = NULL;
72bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
73bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
74bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
75bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::initPorts() {
76bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    OMX_PARAM_PORTDEFINITIONTYPE def;
77bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    InitOMXParams(&def);
78bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
79bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nPortIndex = 0;
80bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDir = OMX_DirInput;
81bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountMin = kNumBuffers;
82bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountActual = def.nBufferCountMin;
83bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferSize = 960 * 6;
84bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bEnabled = OMX_TRUE;
85bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bPopulated = OMX_FALSE;
86bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDomain = OMX_PortDomainAudio;
87bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bBuffersContiguous = OMX_FALSE;
88bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferAlignment = 1;
89bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
90bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.cMIMEType =
91bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const_cast<char *>(MEDIA_MIMETYPE_AUDIO_OPUS);
92bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
93bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.pNativeRender = NULL;
94bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
9517d653523898c01816457743ab376a7b0427611fLajos Molnar    def.format.audio.eEncoding =
9617d653523898c01816457743ab376a7b0427611fLajos Molnar        (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS;
97bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
98bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    addPort(def);
99bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
100bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nPortIndex = 1;
101bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDir = OMX_DirOutput;
102bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountMin = kNumBuffers;
103bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountActual = def.nBufferCountMin;
104bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t);
105bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bEnabled = OMX_TRUE;
106bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bPopulated = OMX_FALSE;
107bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDomain = OMX_PortDomainAudio;
108bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bBuffersContiguous = OMX_FALSE;
109bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferAlignment = 2;
110bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
111bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
112bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.pNativeRender = NULL;
113bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
114bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
115bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
116bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    addPort(def);
117bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
118bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
119bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatus_t SoftOpus::initDecoder() {
120bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return OK;
121bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
122bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
123bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianOMX_ERRORTYPE SoftOpus::internalGetParameter(
124bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_INDEXTYPE index, OMX_PTR params) {
12517d653523898c01816457743ab376a7b0427611fLajos Molnar    switch ((int)index) {
126bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioAndroidOpus:
127bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
128bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
129bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
130bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
131bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (opusParams->nPortIndex != 0) {
132bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
133bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
134bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
135bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nAudioBandWidth = 0;
136bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nSampleRate = kRate;
137bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nBitRate = 0;
138bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
139bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!isConfigured()) {
140bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opusParams->nChannels = 1;
141bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
142bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opusParams->nChannels = mHeader->channels;
143bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
144bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
145bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
146bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
147bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
148bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioPcm:
149bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
150bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
151bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
152bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
153bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (pcmParams->nPortIndex != 1) {
154bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
155bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
156bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
157bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eNumData = OMX_NumericalDataSigned;
158bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eEndian = OMX_EndianBig;
159bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->bInterleaved = OMX_TRUE;
160bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->nBitPerSample = 16;
161bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
162bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
163bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
164bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->nSamplingRate = kRate;
165bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
166bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!isConfigured()) {
167bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                pcmParams->nChannels = 1;
168bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
169bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                pcmParams->nChannels = mHeader->channels;
170bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
171bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
172bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
173bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
174bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
175bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
176bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return SimpleSoftOMXComponent::internalGetParameter(index, params);
177bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
178bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
179bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
180bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianOMX_ERRORTYPE SoftOpus::internalSetParameter(
181bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_INDEXTYPE index, const OMX_PTR params) {
18217d653523898c01816457743ab376a7b0427611fLajos Molnar    switch ((int)index) {
183bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamStandardComponentRole:
184bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
185bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
186bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (const OMX_PARAM_COMPONENTROLETYPE *)params;
187bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
188bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (strncmp((const char *)roleParams->cRole,
189bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                        "audio_decoder.opus",
190bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                        OMX_MAX_STRINGNAME_SIZE - 1)) {
191bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
192bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
193bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
194bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
195bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
196bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
197bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioAndroidOpus:
198bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
199bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
200bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
201bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
202bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (opusParams->nPortIndex != 0) {
203bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
204bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
205bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
206bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
207bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
208bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
209bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
210bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return SimpleSoftOMXComponent::internalSetParameter(index, params);
211bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
212bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
213bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
214bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianbool SoftOpus::isConfigured() const {
215bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return mInputBufferCount >= 1;
216bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
217bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
218bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic uint16_t ReadLE16(const uint8_t *data, size_t data_size,
219bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                         uint32_t read_offset) {
220bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (read_offset + 1 > data_size)
221bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return 0;
222bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    uint16_t val;
223bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    val = data[read_offset];
224bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    val |= data[read_offset + 1] << 8;
225bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return val;
226bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
227bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
228bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
229bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// mappings for up to 8 channels. This information is part of the Vorbis I
230bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Specification:
231bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
232bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kMaxChannels = 8;
233bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
234bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Maximum packet size used in Xiph's opusdec.
235bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
236bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
237bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Default audio output channel layout. Used to initialize |stream_map| in
238bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// OpusHeader, and passed to opus_multistream_decoder_create() when the header
239bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// does not contain mapping information. The values are valid only for mono and
240bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// stereo output: Opus streams with more than 2 channels require a stream map.
241bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kMaxChannelsWithDefaultLayout = 2;
242bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
243bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
244bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
245bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic bool ParseOpusHeader(const uint8_t *data, size_t data_size,
246bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                            OpusHeader* header) {
247bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Size of the Opus header excluding optional mapping information.
24817d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderSize = 19;
249bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
250bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the channel count byte in the Opus header.
25117d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderChannelsOffset = 9;
252bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
253bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the pre-skip value in the Opus header.
25417d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderSkipSamplesOffset = 10;
255bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
256bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the gain value in the Opus header.
25717d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderGainOffset = 16;
258bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
259bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the channel mapping byte in the Opus header.
26017d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderChannelMappingOffset = 18;
261bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
262bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Opus Header contains a stream map. The mapping values are in the header
263bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
264bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // data contains stream count, coupling information, and per channel mapping
265bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // values:
266bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 0: Number of streams.
267bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 1: Number coupled.
268bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
269bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //             values.
27017d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
27117d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
27217d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
273bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
274bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (data_size < kOpusHeaderSize) {
275bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Header size is too small.");
276bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
277bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
278bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->channels = *(data + kOpusHeaderChannelsOffset);
279bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
280bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (header->channels <= 0 || header->channels > kMaxChannels) {
281bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Invalid Header, wrong channel count: %d", header->channels);
282bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
283bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
284bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->skip_samples = ReadLE16(data, data_size,
285bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                        kOpusHeaderSkipSamplesOffset);
286bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->gain_db = static_cast<int16_t>(
287bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              ReadLE16(data, data_size,
288bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                       kOpusHeaderGainOffset));
289bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
290bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (!header->channel_mapping) {
291bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (header->channels > kMaxChannelsWithDefaultLayout) {
292bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            ALOGV("Invalid Header, missing stream map.");
293bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return false;
294bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
295bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->num_streams = 1;
296bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->num_coupled = header->channels > 1;
297bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->stream_map[0] = 0;
298bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->stream_map[1] = 1;
299bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return true;
300bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
301bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
302bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Invalid stream map; insufficient data for current channel "
303bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian              "count: %d", header->channels);
304bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
305bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
306bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
307bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
308bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (header->num_streams + header->num_coupled != header->channels) {
309bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Inconsistent channel mapping.");
310bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
311bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
312bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    for (int i = 0; i < header->channels; ++i)
313bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
314bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return true;
315bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
316bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
317bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Convert nanoseconds to number of samples.
318bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic uint64_t ns_to_samples(uint64_t ns, int kRate) {
319bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return static_cast<double>(ns) * kRate / 1000000000;
320bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
321bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
322bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onQueueFilled(OMX_U32 portIndex) {
323bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    List<BufferInfo *> &inQueue = getPortQueue(0);
324bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    List<BufferInfo *> &outQueue = getPortQueue(1);
325bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
326bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mOutputPortSettingsChange != NONE) {
327bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
328bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
329bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
330bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex == 0 && mInputBufferCount < 3) {
331bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *info = *inQueue.begin();
332bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *header = info->mHeader;
333bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
334bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint8_t *data = header->pBuffer + header->nOffset;
335bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        size_t size = header->nFilledLen;
336bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
337bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (mInputBufferCount == 0) {
338bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(mHeader == NULL);
339bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mHeader = new OpusHeader();
340bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            memset(mHeader, 0, sizeof(*mHeader));
341bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!ParseOpusHeader(data, size, mHeader)) {
342bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("Parsing Opus Header failed.");
343bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
344bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
345bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
346bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
347bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            uint8_t channel_mapping[kMaxChannels] = {0};
348bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            memcpy(&channel_mapping,
349bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                   kDefaultOpusChannelLayout,
350bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                   kMaxChannelsWithDefaultLayout);
351bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
352bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            int status = OPUS_INVALID_STATE;
353bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mDecoder = opus_multistream_decoder_create(kRate,
354bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->channels,
355bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->num_streams,
356bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->num_coupled,
357bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       channel_mapping,
358bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       &status);
359bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!mDecoder || status != OPUS_OK) {
360bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("opus_multistream_decoder_create failed status=%s",
361bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                      opus_strerror(status));
362bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
363bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
364bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
365bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            status =
366bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opus_multistream_decoder_ctl(mDecoder,
367bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                             OPUS_SET_GAIN(mHeader->gain_db));
368bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (status != OPUS_OK) {
369bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("Failed to set OPUS header gain; status=%s",
370bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                      opus_strerror(status));
371bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
372bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
373bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
374bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        } else if (mInputBufferCount == 1) {
375bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mCodecDelay = ns_to_samples(
376bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              *(reinterpret_cast<int64_t*>(header->pBuffer +
377bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                           header->nOffset)),
378bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              kRate);
379bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSamplesToDiscard = mCodecDelay;
380bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        } else {
381bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSeekPreRoll = ns_to_samples(
382bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                               *(reinterpret_cast<int64_t*>(header->pBuffer +
383bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                            header->nOffset)),
384bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                               kRate);
385bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
386bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = AWAITING_DISABLED;
387bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
388bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
389bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inQueue.erase(inQueue.begin());
390bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        info->mOwnedByUs = false;
391bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyEmptyBufferDone(header);
392bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ++mInputBufferCount;
393bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
394bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
395bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
396bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    while (!inQueue.empty() && !outQueue.empty()) {
397bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *inInfo = *inQueue.begin();
398bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
399bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
400bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *outInfo = *outQueue.begin();
401bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
402bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
403bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
404bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            inQueue.erase(inQueue.begin());
405bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            inInfo->mOwnedByUs = false;
406bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notifyEmptyBufferDone(inHeader);
407bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
408bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outHeader->nFilledLen = 0;
409bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
410bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
411bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outQueue.erase(outQueue.begin());
412bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outInfo->mOwnedByUs = false;
413bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notifyFillBufferDone(outHeader);
414bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return;
415bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
416bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
417bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nOffset == 0) {
418bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mAnchorTimeUs = inHeader->nTimeStamp;
419bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mNumFramesOutput = 0;
420bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
421bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
422bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // When seeking to zero, |mCodecDelay| samples has to be discarded
423bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // instead of |mSeekPreRoll| samples (as we would when seeking to any
424bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // other timestamp).
425bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nTimeStamp == 0) {
426bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSamplesToDiscard = mCodecDelay;
427bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
428bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
429bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
430bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint32_t size = inHeader->nFilledLen;
431bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
432bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        int numFrames = opus_multistream_decode(mDecoder,
433bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                data,
434bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                size,
435bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                (int16_t *)outHeader->pBuffer,
436bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                kMaxOpusOutputPacketSizeSamples,
437bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                0);
438bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (numFrames < 0) {
439bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            ALOGE("opus_multistream_decode returned %d", numFrames);
440bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
441bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return;
442bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
443bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
444bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nOffset = 0;
445bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (mSamplesToDiscard > 0) {
446bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (mSamplesToDiscard > numFrames) {
447bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                mSamplesToDiscard -= numFrames;
448bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                numFrames = 0;
449bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
450bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                numFrames -= mSamplesToDiscard;
451bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) *
452bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                     mHeader->channels;
453bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                mSamplesToDiscard = 0;
454bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
455bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
456bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
457bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
458bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nFlags = 0;
459bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
460bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nTimeStamp = mAnchorTimeUs +
461bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                (mNumFramesOutput * 1000000ll) /
462bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                kRate;
463bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
464bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mNumFramesOutput += numFrames;
465bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
466bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inInfo->mOwnedByUs = false;
467bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inQueue.erase(inQueue.begin());
468bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inInfo = NULL;
469bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyEmptyBufferDone(inHeader);
470bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inHeader = NULL;
471bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
472bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outInfo->mOwnedByUs = false;
473bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outQueue.erase(outQueue.begin());
474bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outInfo = NULL;
475bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyFillBufferDone(outHeader);
476bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader = NULL;
477bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
478bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ++mInputBufferCount;
479bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
480bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
481bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
482bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) {
483bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex == 0 && mDecoder != NULL) {
484bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // Make sure that the next buffer output does not still
485bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // depend on fragments from the last one decoded.
486bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mNumFramesOutput = 0;
487bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
488bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mAnchorTimeUs = 0;
489bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mSamplesToDiscard = mSeekPreRoll;
490bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
491bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
492bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
493bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onReset() {
494bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mInputBufferCount = 0;
495bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mNumFramesOutput = 0;
496bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mDecoder != NULL) {
497bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_destroy(mDecoder);
498bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mDecoder = NULL;
499bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
500bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mHeader != NULL) {
501bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        delete mHeader;
502bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mHeader = NULL;
503bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
504bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
505bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mOutputPortSettingsChange = NONE;
506bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
507bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
508bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
509bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex != 1) {
510bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
511bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
512bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
513bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    switch (mOutputPortSettingsChange) {
514bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case NONE:
515bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
516bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
517bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case AWAITING_DISABLED:
518bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
519bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(!enabled);
520bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = AWAITING_ENABLED;
521bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
522bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
523bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
524bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
525bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
526bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
527bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(enabled);
528bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = NONE;
529bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
530bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
531bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
532bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
533bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
534bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}  // namespace android
535bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
536bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianandroid::SoftOMXComponent *createSoftOMXComponent(
537bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const char *name, const OMX_CALLBACKTYPE *callbacks,
538bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
539bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return new android::SoftOpus(name, callbacks, appData, component);
540bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
541