SoftGSM.cpp revision 51f59b41eae9c4f493ebfd0972cee951895bdf19
1/*
2 * Copyright (C) 2012 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17//#define LOG_NDEBUG 0
18#define LOG_TAG "SoftGSM"
19#include <utils/Log.h>
20
21#include "SoftGSM.h"
22
23#include <media/stagefright/foundation/ADebug.h>
24#include <media/stagefright/MediaDefs.h>
25
26namespace android {
27
28template<class T>
29static void InitOMXParams(T *params) {
30    params->nSize = sizeof(T);
31    params->nVersion.s.nVersionMajor = 1;
32    params->nVersion.s.nVersionMinor = 0;
33    params->nVersion.s.nRevision = 0;
34    params->nVersion.s.nStep = 0;
35}
36
37SoftGSM::SoftGSM(
38        const char *name,
39        const OMX_CALLBACKTYPE *callbacks,
40        OMX_PTR appData,
41        OMX_COMPONENTTYPE **component)
42    : SimpleSoftOMXComponent(name, callbacks, appData, component),
43      mSignalledError(false) {
44
45    CHECK(!strcmp(name, "OMX.google.gsm.decoder"));
46
47    mGsm = gsm_create();
48    CHECK(mGsm);
49    int msopt = 1;
50    gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
51
52    initPorts();
53}
54
55SoftGSM::~SoftGSM() {
56    gsm_destroy(mGsm);
57}
58
59void SoftGSM::initPorts() {
60    OMX_PARAM_PORTDEFINITIONTYPE def;
61    InitOMXParams(&def);
62
63    def.nPortIndex = 0;
64    def.eDir = OMX_DirInput;
65    def.nBufferCountMin = kNumBuffers;
66    def.nBufferCountActual = def.nBufferCountMin;
67    def.nBufferSize = sizeof(gsm_frame);
68    def.bEnabled = OMX_TRUE;
69    def.bPopulated = OMX_FALSE;
70    def.eDomain = OMX_PortDomainAudio;
71    def.bBuffersContiguous = OMX_FALSE;
72    def.nBufferAlignment = 1;
73
74    def.format.audio.cMIMEType =
75        const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MSGSM);
76
77    def.format.audio.pNativeRender = NULL;
78    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
79    def.format.audio.eEncoding = OMX_AUDIO_CodingGSMFR;
80
81    addPort(def);
82
83    def.nPortIndex = 1;
84    def.eDir = OMX_DirOutput;
85    def.nBufferCountMin = kNumBuffers;
86    def.nBufferCountActual = def.nBufferCountMin;
87    def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t);
88    def.bEnabled = OMX_TRUE;
89    def.bPopulated = OMX_FALSE;
90    def.eDomain = OMX_PortDomainAudio;
91    def.bBuffersContiguous = OMX_FALSE;
92    def.nBufferAlignment = 2;
93
94    def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
95    def.format.audio.pNativeRender = NULL;
96    def.format.audio.bFlagErrorConcealment = OMX_FALSE;
97    def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
98
99    addPort(def);
100}
101
102OMX_ERRORTYPE SoftGSM::internalGetParameter(
103        OMX_INDEXTYPE index, OMX_PTR params) {
104    switch (index) {
105        case OMX_IndexParamAudioPcm:
106        {
107            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
108                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
109
110            if (!isValidOMXParam(pcmParams)) {
111                return OMX_ErrorBadParameter;
112            }
113
114            if (pcmParams->nPortIndex > 1) {
115                return OMX_ErrorUndefined;
116            }
117
118            pcmParams->eNumData = OMX_NumericalDataSigned;
119            pcmParams->eEndian = OMX_EndianBig;
120            pcmParams->bInterleaved = OMX_TRUE;
121            pcmParams->nBitPerSample = 16;
122            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
123            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
124            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
125
126            pcmParams->nChannels = 1;
127            pcmParams->nSamplingRate = 8000;
128
129            return OMX_ErrorNone;
130        }
131
132        default:
133            return SimpleSoftOMXComponent::internalGetParameter(index, params);
134    }
135}
136
137OMX_ERRORTYPE SoftGSM::internalSetParameter(
138        OMX_INDEXTYPE index, const OMX_PTR params) {
139    switch (index) {
140        case OMX_IndexParamAudioPcm:
141        {
142            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
143                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
144
145            if (!isValidOMXParam(pcmParams)) {
146                return OMX_ErrorBadParameter;
147            }
148
149            if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
150                return OMX_ErrorUndefined;
151            }
152
153            if (pcmParams->nChannels != 1) {
154                return OMX_ErrorUndefined;
155            }
156
157            if (pcmParams->nSamplingRate != 8000) {
158                return OMX_ErrorUndefined;
159            }
160
161            return OMX_ErrorNone;
162        }
163
164        case OMX_IndexParamStandardComponentRole:
165        {
166            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
167                (const OMX_PARAM_COMPONENTROLETYPE *)params;
168
169            if (!isValidOMXParam(roleParams)) {
170                return OMX_ErrorBadParameter;
171            }
172
173            if (strncmp((const char *)roleParams->cRole,
174                        "audio_decoder.gsm",
175                        OMX_MAX_STRINGNAME_SIZE - 1)) {
176                return OMX_ErrorUndefined;
177            }
178
179            return OMX_ErrorNone;
180        }
181
182        default:
183            return SimpleSoftOMXComponent::internalSetParameter(index, params);
184    }
185}
186
187void SoftGSM::onQueueFilled(OMX_U32 portIndex) {
188    if (mSignalledError) {
189        return;
190    }
191
192    List<BufferInfo *> &inQueue = getPortQueue(0);
193    List<BufferInfo *> &outQueue = getPortQueue(1);
194
195    while (!inQueue.empty() && !outQueue.empty()) {
196        BufferInfo *inInfo = *inQueue.begin();
197        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
198
199        BufferInfo *outInfo = *outQueue.begin();
200        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
201
202        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
203            inQueue.erase(inQueue.begin());
204            inInfo->mOwnedByUs = false;
205            notifyEmptyBufferDone(inHeader);
206
207            outHeader->nFilledLen = 0;
208            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
209
210            outQueue.erase(outQueue.begin());
211            outInfo->mOwnedByUs = false;
212            notifyFillBufferDone(outHeader);
213            return;
214        }
215
216        if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
217            ALOGE("input buffer too large (%ld).", inHeader->nFilledLen);
218            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
219            mSignalledError = true;
220        }
221
222        if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) {
223            ALOGE("input buffer not multiple of 65 (%ld).", inHeader->nFilledLen);
224            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
225            mSignalledError = true;
226        }
227
228        uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
229
230        int n = mSignalledError ? 0 : DecodeGSM(mGsm,
231                  reinterpret_cast<int16_t *>(outHeader->pBuffer), inputptr, inHeader->nFilledLen);
232
233        outHeader->nTimeStamp = inHeader->nTimeStamp;
234        outHeader->nOffset = 0;
235        outHeader->nFilledLen = n * sizeof(int16_t);
236        outHeader->nFlags = 0;
237
238        inInfo->mOwnedByUs = false;
239        inQueue.erase(inQueue.begin());
240        inInfo = NULL;
241        notifyEmptyBufferDone(inHeader);
242        inHeader = NULL;
243
244        outInfo->mOwnedByUs = false;
245        outQueue.erase(outQueue.begin());
246        outInfo = NULL;
247        notifyFillBufferDone(outHeader);
248        outHeader = NULL;
249    }
250}
251
252
253// static
254int SoftGSM::DecodeGSM(gsm handle,
255        int16_t *out, uint8_t *in, size_t inSize) {
256
257    int ret = 0;
258    while (inSize > 0) {
259        gsm_decode(handle, in, out);
260        in += 33;
261        inSize -= 33;
262        out += 160;
263        ret += 160;
264        gsm_decode(handle, in, out);
265        in += 32;
266        inSize -= 32;
267        out += 160;
268        ret += 160;
269    }
270    return ret;
271}
272
273
274}  // namespace android
275
276android::SoftOMXComponent *createSoftOMXComponent(
277        const char *name, const OMX_CALLBACKTYPE *callbacks,
278        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
279    return new android::SoftGSM(name, callbacks, appData, component);
280}
281
282