SoftGSM.cpp revision d411b4ca2945cd8974a3a78199fce94646950128
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 (pcmParams->nPortIndex > 1) {
111                return OMX_ErrorUndefined;
112            }
113
114            pcmParams->eNumData = OMX_NumericalDataSigned;
115            pcmParams->eEndian = OMX_EndianBig;
116            pcmParams->bInterleaved = OMX_TRUE;
117            pcmParams->nBitPerSample = 16;
118            pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
119            pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
120            pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
121
122            pcmParams->nChannels = 1;
123            pcmParams->nSamplingRate = 8000;
124
125            return OMX_ErrorNone;
126        }
127
128        default:
129            return SimpleSoftOMXComponent::internalGetParameter(index, params);
130    }
131}
132
133OMX_ERRORTYPE SoftGSM::internalSetParameter(
134        OMX_INDEXTYPE index, const OMX_PTR params) {
135    switch (index) {
136        case OMX_IndexParamAudioPcm:
137        {
138            OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
139                (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
140
141            if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
142                return OMX_ErrorUndefined;
143            }
144
145            if (pcmParams->nChannels != 1) {
146                return OMX_ErrorUndefined;
147            }
148
149            if (pcmParams->nSamplingRate != 8000) {
150                return OMX_ErrorUndefined;
151            }
152
153            return OMX_ErrorNone;
154        }
155
156        case OMX_IndexParamStandardComponentRole:
157        {
158            const OMX_PARAM_COMPONENTROLETYPE *roleParams =
159                (const OMX_PARAM_COMPONENTROLETYPE *)params;
160
161            if (strncmp((const char *)roleParams->cRole,
162                        "audio_decoder.gsm",
163                        OMX_MAX_STRINGNAME_SIZE - 1)) {
164                return OMX_ErrorUndefined;
165            }
166
167            return OMX_ErrorNone;
168        }
169
170        default:
171            return SimpleSoftOMXComponent::internalSetParameter(index, params);
172    }
173}
174
175void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) {
176    if (mSignalledError) {
177        return;
178    }
179
180    List<BufferInfo *> &inQueue = getPortQueue(0);
181    List<BufferInfo *> &outQueue = getPortQueue(1);
182
183    while (!inQueue.empty() && !outQueue.empty()) {
184        BufferInfo *inInfo = *inQueue.begin();
185        OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
186
187        BufferInfo *outInfo = *outQueue.begin();
188        OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
189
190        if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
191            inQueue.erase(inQueue.begin());
192            inInfo->mOwnedByUs = false;
193            notifyEmptyBufferDone(inHeader);
194
195            outHeader->nFilledLen = 0;
196            outHeader->nFlags = OMX_BUFFERFLAG_EOS;
197
198            outQueue.erase(outQueue.begin());
199            outInfo->mOwnedByUs = false;
200            notifyFillBufferDone(outHeader);
201            return;
202        }
203
204        if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
205            ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
206            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
207            mSignalledError = true;
208        }
209
210        if(((inHeader->nFilledLen / 65) * 65) != inHeader->nFilledLen) {
211            ALOGE("input buffer not multiple of 65 (%d).", inHeader->nFilledLen);
212            notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
213            mSignalledError = true;
214        }
215
216        uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
217
218        int n = mSignalledError ? 0 : DecodeGSM(mGsm,
219                  reinterpret_cast<int16_t *>(outHeader->pBuffer), inputptr, inHeader->nFilledLen);
220
221        outHeader->nTimeStamp = inHeader->nTimeStamp;
222        outHeader->nOffset = 0;
223        outHeader->nFilledLen = n * sizeof(int16_t);
224        outHeader->nFlags = 0;
225
226        inInfo->mOwnedByUs = false;
227        inQueue.erase(inQueue.begin());
228        inInfo = NULL;
229        notifyEmptyBufferDone(inHeader);
230        inHeader = NULL;
231
232        outInfo->mOwnedByUs = false;
233        outQueue.erase(outQueue.begin());
234        outInfo = NULL;
235        notifyFillBufferDone(outHeader);
236        outHeader = NULL;
237    }
238}
239
240
241// static
242int SoftGSM::DecodeGSM(gsm handle,
243        int16_t *out, uint8_t *in, size_t inSize) {
244
245    int ret = 0;
246    while (inSize > 0) {
247        gsm_decode(handle, in, out);
248        in += 33;
249        inSize -= 33;
250        out += 160;
251        ret += 160;
252        gsm_decode(handle, in, out);
253        in += 32;
254        inSize -= 32;
255        out += 160;
256        ret += 160;
257    }
258    return ret;
259}
260
261
262}  // namespace android
263
264android::SoftOMXComponent *createSoftOMXComponent(
265        const char *name, const OMX_CALLBACKTYPE *callbacks,
266        OMX_PTR appData, OMX_COMPONENTTYPE **component) {
267    return new android::SoftGSM(name, callbacks, appData, component);
268}
269
270