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
3708e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian// Opus uses Vorbis channel mapping, and Vorbis channel mapping specifies
3808e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian// mappings for up to 8 channels. This information is part of the Vorbis I
3908e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian// Specification:
4008e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian// http://www.xiph.org/vorbis/doc/Vorbis_I_spec.html
4108e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanianstatic const int kMaxChannels = 8;
4208e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian
43bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramaniantemplate<class T>
44bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic void InitOMXParams(T *params) {
45bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nSize = sizeof(T);
46bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nVersionMajor = 1;
47bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nVersionMinor = 0;
48bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nRevision = 0;
49bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    params->nVersion.s.nStep = 0;
50bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
51bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
52bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianSoftOpus::SoftOpus(
53bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const char *name,
54bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const OMX_CALLBACKTYPE *callbacks,
55bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_PTR appData,
56bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_COMPONENTTYPE **component)
57bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    : SimpleSoftOMXComponent(name, callbacks, appData, component),
58bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mInputBufferCount(0),
59bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mDecoder(NULL),
60bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mHeader(NULL),
61bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mCodecDelay(0),
62bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mSeekPreRoll(0),
63bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mAnchorTimeUs(0),
64bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mNumFramesOutput(0),
65bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      mOutputPortSettingsChange(NONE) {
66bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    initPorts();
67bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    CHECK_EQ(initDecoder(), (status_t)OK);
68bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
69bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
70bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianSoftOpus::~SoftOpus() {
71bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mDecoder != NULL) {
72bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_destroy(mDecoder);
73bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mDecoder = NULL;
74bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
75bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mHeader != NULL) {
76bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        delete mHeader;
77bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mHeader = NULL;
78bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
79bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
80bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
81bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::initPorts() {
82bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    OMX_PARAM_PORTDEFINITIONTYPE def;
83bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    InitOMXParams(&def);
84bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
85bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nPortIndex = 0;
86bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDir = OMX_DirInput;
87bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountMin = kNumBuffers;
88bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountActual = def.nBufferCountMin;
89bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferSize = 960 * 6;
90bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bEnabled = OMX_TRUE;
91bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bPopulated = OMX_FALSE;
92bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDomain = OMX_PortDomainAudio;
93bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bBuffersContiguous = OMX_FALSE;
94bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferAlignment = 1;
95bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
96bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.cMIMEType =
97bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const_cast<char *>(MEDIA_MIMETYPE_AUDIO_OPUS);
98bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
99bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.pNativeRender = NULL;
100bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
10117d653523898c01816457743ab376a7b0427611fLajos Molnar    def.format.audio.eEncoding =
10217d653523898c01816457743ab376a7b0427611fLajos Molnar        (OMX_AUDIO_CODINGTYPE)OMX_AUDIO_CodingAndroidOPUS;
103bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
104bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    addPort(def);
105bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
106bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nPortIndex = 1;
107bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDir = OMX_DirOutput;
108bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountMin = kNumBuffers;
109bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferCountActual = def.nBufferCountMin;
11008e8227514f5ab99822dfae8b4d39414646ff59dVignesh Venkatasubramanian    def.nBufferSize = kMaxNumSamplesPerBuffer * sizeof(int16_t) * kMaxChannels;
111bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bEnabled = OMX_TRUE;
112bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bPopulated = OMX_FALSE;
113bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.eDomain = OMX_PortDomainAudio;
114bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.bBuffersContiguous = OMX_FALSE;
115bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.nBufferAlignment = 2;
116bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
117bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
118bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.pNativeRender = NULL;
119bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
120bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
121bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
122bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    addPort(def);
123bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
124bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
125bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatus_t SoftOpus::initDecoder() {
126bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return OK;
127bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
128bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
129bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianOMX_ERRORTYPE SoftOpus::internalGetParameter(
130bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_INDEXTYPE index, OMX_PTR params) {
13117d653523898c01816457743ab376a7b0427611fLajos Molnar    switch ((int)index) {
132bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioAndroidOpus:
133bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
134bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
135bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
136bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
1372720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            if (!isValidOMXParam(opusParams)) {
1382720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen                return OMX_ErrorBadParameter;
1392720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            }
1402720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen
141bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (opusParams->nPortIndex != 0) {
142bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
143bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
144bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
145bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nAudioBandWidth = 0;
146bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nSampleRate = kRate;
147bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            opusParams->nBitRate = 0;
148bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
149bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!isConfigured()) {
150bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opusParams->nChannels = 1;
151bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
152bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opusParams->nChannels = mHeader->channels;
153bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
154bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
155bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
156bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
157bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
158bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioPcm:
159bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
160bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
161bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
162bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
1632720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            if (!isValidOMXParam(pcmParams)) {
1642720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen                return OMX_ErrorBadParameter;
1652720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            }
1662720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen
167bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (pcmParams->nPortIndex != 1) {
168bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
169bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
170bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
171bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eNumData = OMX_NumericalDataSigned;
172bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eEndian = OMX_EndianBig;
173bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->bInterleaved = OMX_TRUE;
174bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->nBitPerSample = 16;
175bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
176bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
177bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
178bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            pcmParams->nSamplingRate = kRate;
179bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
180bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!isConfigured()) {
181bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                pcmParams->nChannels = 1;
182bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
183bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                pcmParams->nChannels = mHeader->channels;
184bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
185bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
186bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
187bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
188bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
189bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
190bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return SimpleSoftOMXComponent::internalGetParameter(index, params);
191bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
192bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
193bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
194bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh VenkatasubramanianOMX_ERRORTYPE SoftOpus::internalSetParameter(
195bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_INDEXTYPE index, const OMX_PTR params) {
19617d653523898c01816457743ab376a7b0427611fLajos Molnar    switch ((int)index) {
197bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamStandardComponentRole:
198bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
199bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
200bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (const OMX_PARAM_COMPONENTROLETYPE *)params;
201bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
2022720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            if (!isValidOMXParam(roleParams)) {
2032720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen                return OMX_ErrorBadParameter;
2042720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            }
2052720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen
206bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (strncmp((const char *)roleParams->cRole,
207bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                        "audio_decoder.opus",
208bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                        OMX_MAX_STRINGNAME_SIZE - 1)) {
209bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
210bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
211bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
212bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
213bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
214bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
215bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case OMX_IndexParamAudioAndroidOpus:
216bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
217bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *opusParams =
218bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                (const OMX_AUDIO_PARAM_ANDROID_OPUSTYPE *)params;
219bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
2202720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            if (!isValidOMXParam(opusParams)) {
2212720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen                return OMX_ErrorBadParameter;
2222720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen            }
2232720c8b094cfa58de314daa8e5e4fb4fa81fe3b2Marco Nelissen
224bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (opusParams->nPortIndex != 0) {
225bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return OMX_ErrorUndefined;
226bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
227bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
228bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return OMX_ErrorNone;
229bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
230bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
231bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
232bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return SimpleSoftOMXComponent::internalSetParameter(index, params);
233bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
234bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
235bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
236bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianbool SoftOpus::isConfigured() const {
237bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return mInputBufferCount >= 1;
238bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
239bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
240bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic uint16_t ReadLE16(const uint8_t *data, size_t data_size,
241bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                         uint32_t read_offset) {
242bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (read_offset + 1 > data_size)
243bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return 0;
244bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    uint16_t val;
245bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    val = data[read_offset];
246bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    val |= data[read_offset + 1] << 8;
247bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return val;
248bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
249bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
250bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Maximum packet size used in Xiph's opusdec.
251bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kMaxOpusOutputPacketSizeSamples = 960 * 6;
252bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
253bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Default audio output channel layout. Used to initialize |stream_map| in
254bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// OpusHeader, and passed to opus_multistream_decoder_create() when the header
255bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// does not contain mapping information. The values are valid only for mono and
256bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// stereo output: Opus streams with more than 2 channels require a stream map.
257bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const int kMaxChannelsWithDefaultLayout = 2;
258bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic const uint8_t kDefaultOpusChannelLayout[kMaxChannelsWithDefaultLayout] = { 0, 1 };
259bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
260bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Parses Opus Header. Header spec: http://wiki.xiph.org/OggOpus#ID_Header
261bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic bool ParseOpusHeader(const uint8_t *data, size_t data_size,
262bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                            OpusHeader* header) {
263bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Size of the Opus header excluding optional mapping information.
26417d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderSize = 19;
265bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
266bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the channel count byte in the Opus header.
26717d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderChannelsOffset = 9;
268bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
269bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the pre-skip value in the Opus header.
27017d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderSkipSamplesOffset = 10;
271bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
272bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the gain value in the Opus header.
27317d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderGainOffset = 16;
274bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
275bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Offset to the channel mapping byte in the Opus header.
27617d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderChannelMappingOffset = 18;
277bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
278bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // Opus Header contains a stream map. The mapping values are in the header
279bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // beyond the always present |kOpusHeaderSize| bytes of data. The mapping
280bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // data contains stream count, coupling information, and per channel mapping
281bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    // values:
282bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 0: Number of streams.
283bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 1: Number coupled.
284bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //   - Byte 2: Starting at byte 2 are |header->channels| uint8 mapping
285bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    //             values.
28617d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderNumStreamsOffset = kOpusHeaderSize;
28717d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderNumCoupledOffset = kOpusHeaderNumStreamsOffset + 1;
28817d653523898c01816457743ab376a7b0427611fLajos Molnar    const size_t kOpusHeaderStreamMapOffset = kOpusHeaderNumStreamsOffset + 2;
289bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
290bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (data_size < kOpusHeaderSize) {
291bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Header size is too small.");
292bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
293bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
294bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->channels = *(data + kOpusHeaderChannelsOffset);
295bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
296bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (header->channels <= 0 || header->channels > kMaxChannels) {
297bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Invalid Header, wrong channel count: %d", header->channels);
298bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
299bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
300bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->skip_samples = ReadLE16(data, data_size,
301bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                        kOpusHeaderSkipSamplesOffset);
302bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->gain_db = static_cast<int16_t>(
303bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              ReadLE16(data, data_size,
304bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                       kOpusHeaderGainOffset));
305bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->channel_mapping = *(data + kOpusHeaderChannelMappingOffset);
306bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (!header->channel_mapping) {
307bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (header->channels > kMaxChannelsWithDefaultLayout) {
308bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            ALOGV("Invalid Header, missing stream map.");
309bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return false;
310bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
311bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->num_streams = 1;
312bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->num_coupled = header->channels > 1;
313bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->stream_map[0] = 0;
314bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        header->stream_map[1] = 1;
315bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return true;
316bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
317bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (data_size < kOpusHeaderStreamMapOffset + header->channels) {
318bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Invalid stream map; insufficient data for current channel "
319bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian              "count: %d", header->channels);
320bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
321bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
322bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->num_streams = *(data + kOpusHeaderNumStreamsOffset);
323bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    header->num_coupled = *(data + kOpusHeaderNumCoupledOffset);
324bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (header->num_streams + header->num_coupled != header->channels) {
325bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ALOGV("Inconsistent channel mapping.");
326bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return false;
327bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
328bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    for (int i = 0; i < header->channels; ++i)
329bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian      header->stream_map[i] = *(data + kOpusHeaderStreamMapOffset + i);
330bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return true;
331bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
332bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
333bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian// Convert nanoseconds to number of samples.
334bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianstatic uint64_t ns_to_samples(uint64_t ns, int kRate) {
335bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return static_cast<double>(ns) * kRate / 1000000000;
336bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
337bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
338bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onQueueFilled(OMX_U32 portIndex) {
339bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    List<BufferInfo *> &inQueue = getPortQueue(0);
340bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    List<BufferInfo *> &outQueue = getPortQueue(1);
341bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
342bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mOutputPortSettingsChange != NONE) {
343bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
344bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
345bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
346bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex == 0 && mInputBufferCount < 3) {
347bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *info = *inQueue.begin();
348bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *header = info->mHeader;
349bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
350bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint8_t *data = header->pBuffer + header->nOffset;
351bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        size_t size = header->nFilledLen;
352bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
353bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (mInputBufferCount == 0) {
354bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(mHeader == NULL);
355bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mHeader = new OpusHeader();
356bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            memset(mHeader, 0, sizeof(*mHeader));
357bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!ParseOpusHeader(data, size, mHeader)) {
358bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("Parsing Opus Header failed.");
359bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
360bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
361bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
362bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
363bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            uint8_t channel_mapping[kMaxChannels] = {0};
3649b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian            if (mHeader->channels <= kMaxChannelsWithDefaultLayout) {
3659b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                memcpy(&channel_mapping,
3669b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                       kDefaultOpusChannelLayout,
3679b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                       kMaxChannelsWithDefaultLayout);
3689b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian            } else {
3699b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                memcpy(&channel_mapping,
3709b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                       mHeader->stream_map,
3719b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian                       mHeader->channels);
3729b4b24a46f3f76ebb186df8bc01c58848af02108Vignesh Venkatasubramanian            }
373bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
374bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            int status = OPUS_INVALID_STATE;
375bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mDecoder = opus_multistream_decoder_create(kRate,
376bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->channels,
377bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->num_streams,
378bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       mHeader->num_coupled,
379bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       channel_mapping,
380bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                       &status);
381bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (!mDecoder || status != OPUS_OK) {
382bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("opus_multistream_decoder_create failed status=%s",
383bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                      opus_strerror(status));
384bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
385bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
386bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
387bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            status =
388bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                opus_multistream_decoder_ctl(mDecoder,
389bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                             OPUS_SET_GAIN(mHeader->gain_db));
390bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (status != OPUS_OK) {
391bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                ALOGV("Failed to set OPUS header gain; status=%s",
392bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                      opus_strerror(status));
393bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
394bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                return;
395bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
396bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        } else if (mInputBufferCount == 1) {
397bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mCodecDelay = ns_to_samples(
398bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              *(reinterpret_cast<int64_t*>(header->pBuffer +
399bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                           header->nOffset)),
400bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                              kRate);
401bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSamplesToDiscard = mCodecDelay;
402bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        } else {
403bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSeekPreRoll = ns_to_samples(
404bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                               *(reinterpret_cast<int64_t*>(header->pBuffer +
405bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                            header->nOffset)),
406bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                               kRate);
407bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notify(OMX_EventPortSettingsChanged, 1, 0, NULL);
408bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = AWAITING_DISABLED;
409bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
410bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
411bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inQueue.erase(inQueue.begin());
412bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        info->mOwnedByUs = false;
413bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyEmptyBufferDone(header);
414bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ++mInputBufferCount;
415bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
416bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
417bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
418bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    while (!inQueue.empty() && !outQueue.empty()) {
419bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *inInfo = *inQueue.begin();
420bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
421bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
4221b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian        // Ignore CSD re-submissions.
4231b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian        if (inHeader->nFlags & OMX_BUFFERFLAG_CODECCONFIG) {
4241b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian            inQueue.erase(inQueue.begin());
4251b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian            inInfo->mOwnedByUs = false;
4261b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian            notifyEmptyBufferDone(inHeader);
4271b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian            return;
4281b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian        }
4291b30bde3d4447e4c9b767c68584b8997bd930720Vignesh Venkatasubramanian
430bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        BufferInfo *outInfo = *outQueue.begin();
431bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
432bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
433bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
434bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            inQueue.erase(inQueue.begin());
435bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            inInfo->mOwnedByUs = false;
436bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notifyEmptyBufferDone(inHeader);
437bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
438bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outHeader->nFilledLen = 0;
439bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
440bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
441bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outQueue.erase(outQueue.begin());
442bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            outInfo->mOwnedByUs = false;
443bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notifyFillBufferDone(outHeader);
444bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return;
445bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
446bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
447bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nOffset == 0) {
448bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mAnchorTimeUs = inHeader->nTimeStamp;
449bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mNumFramesOutput = 0;
450bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
451bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
452bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // When seeking to zero, |mCodecDelay| samples has to be discarded
453bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // instead of |mSeekPreRoll| samples (as we would when seeking to any
454bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // other timestamp).
455bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (inHeader->nTimeStamp == 0) {
456bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mSamplesToDiscard = mCodecDelay;
457bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
458bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
459bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint8_t *data = inHeader->pBuffer + inHeader->nOffset;
460bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const uint32_t size = inHeader->nFilledLen;
461e6a2b5d7d2e9fa8db10ccb911d472c0fefa77557Wonsik Kim        size_t frameSize = kMaxOpusOutputPacketSizeSamples;
462e6a2b5d7d2e9fa8db10ccb911d472c0fefa77557Wonsik Kim        if (frameSize > outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels) {
463e6a2b5d7d2e9fa8db10ccb911d472c0fefa77557Wonsik Kim            frameSize = outHeader->nAllocLen / sizeof(int16_t) / mHeader->channels;
464ff64ea33382081f46d4b1061df00298bbbe3dd65Wonsik Kim            android_errorWriteLog(0x534e4554, "27833616");
465e6a2b5d7d2e9fa8db10ccb911d472c0fefa77557Wonsik Kim        }
466bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
467bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        int numFrames = opus_multistream_decode(mDecoder,
468bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                data,
469bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                size,
470bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                (int16_t *)outHeader->pBuffer,
471e6a2b5d7d2e9fa8db10ccb911d472c0fefa77557Wonsik Kim                                                frameSize,
472bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                                0);
473bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (numFrames < 0) {
474bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            ALOGE("opus_multistream_decode returned %d", numFrames);
475bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
476bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            return;
477bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
478bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
479bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nOffset = 0;
480bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        if (mSamplesToDiscard > 0) {
481bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            if (mSamplesToDiscard > numFrames) {
482bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                mSamplesToDiscard -= numFrames;
483bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                numFrames = 0;
484bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            } else {
485bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                numFrames -= mSamplesToDiscard;
486bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                outHeader->nOffset = mSamplesToDiscard * sizeof(int16_t) *
487bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                     mHeader->channels;
488bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                mSamplesToDiscard = 0;
489bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            }
490bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
491bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
492bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nFilledLen = numFrames * sizeof(int16_t) * mHeader->channels;
493bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nFlags = 0;
494bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
495bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader->nTimeStamp = mAnchorTimeUs +
496bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                (mNumFramesOutput * 1000000ll) /
497bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian                                kRate;
498bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
499bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mNumFramesOutput += numFrames;
500bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
501bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inInfo->mOwnedByUs = false;
502bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inQueue.erase(inQueue.begin());
503bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inInfo = NULL;
504bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyEmptyBufferDone(inHeader);
505bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        inHeader = NULL;
506bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
507bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outInfo->mOwnedByUs = false;
508bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outQueue.erase(outQueue.begin());
509bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outInfo = NULL;
510bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        notifyFillBufferDone(outHeader);
511bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        outHeader = NULL;
512bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
513bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        ++mInputBufferCount;
514bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
515bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
516bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
517bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onPortFlushCompleted(OMX_U32 portIndex) {
518bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex == 0 && mDecoder != NULL) {
519bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // Make sure that the next buffer output does not still
520bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        // depend on fragments from the last one decoded.
521bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mNumFramesOutput = 0;
522bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_ctl(mDecoder, OPUS_RESET_STATE);
523bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mAnchorTimeUs = 0;
524bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mSamplesToDiscard = mSeekPreRoll;
525bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
526bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
527bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
528bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onReset() {
529bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mInputBufferCount = 0;
530bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mNumFramesOutput = 0;
531bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mDecoder != NULL) {
532bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        opus_multistream_decoder_destroy(mDecoder);
533bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mDecoder = NULL;
534bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
535bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (mHeader != NULL) {
536bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        delete mHeader;
537bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        mHeader = NULL;
538bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
539bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
540bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    mOutputPortSettingsChange = NONE;
541bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
542bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
543bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianvoid SoftOpus::onPortEnableCompleted(OMX_U32 portIndex, bool enabled) {
544bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    if (portIndex != 1) {
545bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        return;
546bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
547bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
548bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    switch (mOutputPortSettingsChange) {
549bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case NONE:
550bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
551bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
552bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        case AWAITING_DISABLED:
553bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
554bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(!enabled);
555bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = AWAITING_ENABLED;
556bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
557bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
558bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
559bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        default:
560bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        {
561bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK_EQ((int)mOutputPortSettingsChange, (int)AWAITING_ENABLED);
562bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            CHECK(enabled);
563bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            mOutputPortSettingsChange = NONE;
564bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian            break;
565bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        }
566bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    }
567bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
568bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
569bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}  // namespace android
570bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian
571bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanianandroid::SoftOMXComponent *createSoftOMXComponent(
572bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        const char *name, const OMX_CALLBACKTYPE *callbacks,
573bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
574bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian    return new android::SoftOpus(name, callbacks, appData, component);
575bf927f8ec7979f2b64331c2b2f12a6a5dba05bcaVignesh Venkatasubramanian}
576