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 
26 namespace android {
27 
28 template<class T>
InitOMXParams(T * params)29 static 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 
37 // Microsoft WAV GSM encoding packs two GSM frames into 65 bytes.
38 static const int kMSGSMFrameSize = 65;
39 
SoftGSM(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)40 SoftGSM::SoftGSM(
41         const char *name,
42         const OMX_CALLBACKTYPE *callbacks,
43         OMX_PTR appData,
44         OMX_COMPONENTTYPE **component)
45     : SimpleSoftOMXComponent(name, callbacks, appData, component),
46       mSignalledError(false) {
47 
48     CHECK(!strcmp(name, "OMX.google.gsm.decoder"));
49 
50     mGsm = gsm_create();
51     CHECK(mGsm);
52     int msopt = 1;
53     gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
54 
55     initPorts();
56 }
57 
~SoftGSM()58 SoftGSM::~SoftGSM() {
59     gsm_destroy(mGsm);
60 }
61 
initPorts()62 void SoftGSM::initPorts() {
63     OMX_PARAM_PORTDEFINITIONTYPE def;
64     InitOMXParams(&def);
65 
66     def.nPortIndex = 0;
67     def.eDir = OMX_DirInput;
68     def.nBufferCountMin = kNumBuffers;
69     def.nBufferCountActual = def.nBufferCountMin;
70     def.nBufferSize = 1024 / kMSGSMFrameSize * kMSGSMFrameSize;
71     def.bEnabled = OMX_TRUE;
72     def.bPopulated = OMX_FALSE;
73     def.eDomain = OMX_PortDomainAudio;
74     def.bBuffersContiguous = OMX_FALSE;
75     def.nBufferAlignment = 1;
76 
77     def.format.audio.cMIMEType =
78         const_cast<char *>(MEDIA_MIMETYPE_AUDIO_MSGSM);
79 
80     def.format.audio.pNativeRender = NULL;
81     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
82     def.format.audio.eEncoding = OMX_AUDIO_CodingGSMFR;
83 
84     addPort(def);
85 
86     def.nPortIndex = 1;
87     def.eDir = OMX_DirOutput;
88     def.nBufferCountMin = kNumBuffers;
89     def.nBufferCountActual = def.nBufferCountMin;
90     def.nBufferSize = kMaxNumSamplesPerFrame * sizeof(int16_t);
91     def.bEnabled = OMX_TRUE;
92     def.bPopulated = OMX_FALSE;
93     def.eDomain = OMX_PortDomainAudio;
94     def.bBuffersContiguous = OMX_FALSE;
95     def.nBufferAlignment = 2;
96 
97     def.format.audio.cMIMEType = const_cast<char *>("audio/raw");
98     def.format.audio.pNativeRender = NULL;
99     def.format.audio.bFlagErrorConcealment = OMX_FALSE;
100     def.format.audio.eEncoding = OMX_AUDIO_CodingPCM;
101 
102     addPort(def);
103 }
104 
internalGetParameter(OMX_INDEXTYPE index,OMX_PTR params)105 OMX_ERRORTYPE SoftGSM::internalGetParameter(
106         OMX_INDEXTYPE index, OMX_PTR params) {
107     switch (index) {
108         case OMX_IndexParamAudioPortFormat:
109         {
110             OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
111                 (OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
112 
113             if (!isValidOMXParam(formatParams)) {
114                 return OMX_ErrorBadParameter;
115             }
116 
117             if (formatParams->nPortIndex > 1) {
118                 return OMX_ErrorUndefined;
119             }
120 
121             if (formatParams->nIndex > 0) {
122                 return OMX_ErrorNoMore;
123             }
124 
125             formatParams->eEncoding =
126                 (formatParams->nPortIndex == 0)
127                     ? OMX_AUDIO_CodingGSMFR : OMX_AUDIO_CodingPCM;
128 
129             return OMX_ErrorNone;
130         }
131 
132         case OMX_IndexParamAudioPcm:
133         {
134             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
135                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
136 
137             if (!isValidOMXParam(pcmParams)) {
138                 return OMX_ErrorBadParameter;
139             }
140 
141             if (pcmParams->nPortIndex > 1) {
142                 return OMX_ErrorUndefined;
143             }
144 
145             pcmParams->eNumData = OMX_NumericalDataSigned;
146             pcmParams->eEndian = OMX_EndianBig;
147             pcmParams->bInterleaved = OMX_TRUE;
148             pcmParams->nBitPerSample = 16;
149             pcmParams->ePCMMode = OMX_AUDIO_PCMModeLinear;
150             pcmParams->eChannelMapping[0] = OMX_AUDIO_ChannelLF;
151             pcmParams->eChannelMapping[1] = OMX_AUDIO_ChannelRF;
152 
153             pcmParams->nChannels = 1;
154             pcmParams->nSamplingRate = 8000;
155 
156             return OMX_ErrorNone;
157         }
158 
159         default:
160             return SimpleSoftOMXComponent::internalGetParameter(index, params);
161     }
162 }
163 
internalSetParameter(OMX_INDEXTYPE index,const OMX_PTR params)164 OMX_ERRORTYPE SoftGSM::internalSetParameter(
165         OMX_INDEXTYPE index, const OMX_PTR params) {
166     switch (index) {
167         case OMX_IndexParamAudioPcm:
168         {
169             OMX_AUDIO_PARAM_PCMMODETYPE *pcmParams =
170                 (OMX_AUDIO_PARAM_PCMMODETYPE *)params;
171 
172             if (!isValidOMXParam(pcmParams)) {
173                 return OMX_ErrorBadParameter;
174             }
175 
176             if (pcmParams->nPortIndex != 0 && pcmParams->nPortIndex != 1) {
177                 return OMX_ErrorUndefined;
178             }
179 
180             if (pcmParams->nChannels != 1) {
181                 return OMX_ErrorUndefined;
182             }
183 
184             if (pcmParams->nSamplingRate != 8000) {
185                 return OMX_ErrorUndefined;
186             }
187 
188             return OMX_ErrorNone;
189         }
190 
191         case OMX_IndexParamAudioPortFormat:
192         {
193             const OMX_AUDIO_PARAM_PORTFORMATTYPE *formatParams =
194                 (const OMX_AUDIO_PARAM_PORTFORMATTYPE *)params;
195 
196             if (!isValidOMXParam(formatParams)) {
197                 return OMX_ErrorBadParameter;
198             }
199 
200             if (formatParams->nPortIndex > 1) {
201                 return OMX_ErrorUndefined;
202             }
203 
204             if ((formatParams->nPortIndex == 0
205                         && formatParams->eEncoding != OMX_AUDIO_CodingGSMFR)
206                 || (formatParams->nPortIndex == 1
207                         && formatParams->eEncoding != OMX_AUDIO_CodingPCM)) {
208                 return OMX_ErrorUndefined;
209             }
210 
211             return OMX_ErrorNone;
212         }
213 
214         case OMX_IndexParamStandardComponentRole:
215         {
216             const OMX_PARAM_COMPONENTROLETYPE *roleParams =
217                 (const OMX_PARAM_COMPONENTROLETYPE *)params;
218 
219             if (!isValidOMXParam(roleParams)) {
220                 return OMX_ErrorBadParameter;
221             }
222 
223             if (strncmp((const char *)roleParams->cRole,
224                         "audio_decoder.gsm",
225                         OMX_MAX_STRINGNAME_SIZE - 1)) {
226                 return OMX_ErrorUndefined;
227             }
228 
229             return OMX_ErrorNone;
230         }
231 
232         default:
233             return SimpleSoftOMXComponent::internalSetParameter(index, params);
234     }
235 }
236 
onQueueFilled(OMX_U32)237 void SoftGSM::onQueueFilled(OMX_U32 /* portIndex */) {
238     if (mSignalledError) {
239         return;
240     }
241 
242     List<BufferInfo *> &inQueue = getPortQueue(0);
243     List<BufferInfo *> &outQueue = getPortQueue(1);
244 
245     while (!inQueue.empty() && !outQueue.empty()) {
246         BufferInfo *inInfo = *inQueue.begin();
247         OMX_BUFFERHEADERTYPE *inHeader = inInfo->mHeader;
248 
249         BufferInfo *outInfo = *outQueue.begin();
250         OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
251 
252         if ((inHeader->nFlags & OMX_BUFFERFLAG_EOS) && inHeader->nFilledLen == 0) {
253             inQueue.erase(inQueue.begin());
254             inInfo->mOwnedByUs = false;
255             notifyEmptyBufferDone(inHeader);
256 
257             outHeader->nFilledLen = 0;
258             outHeader->nFlags = OMX_BUFFERFLAG_EOS;
259 
260             outQueue.erase(outQueue.begin());
261             outInfo->mOwnedByUs = false;
262             notifyFillBufferDone(outHeader);
263             return;
264         }
265 
266         if (inHeader->nFilledLen > kMaxNumSamplesPerFrame) {
267             ALOGE("input buffer too large (%d).", inHeader->nFilledLen);
268             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
269             mSignalledError = true;
270         }
271 
272         if(((inHeader->nFilledLen / kMSGSMFrameSize) * kMSGSMFrameSize) != inHeader->nFilledLen) {
273             ALOGE("input buffer not multiple of %d (%d).", kMSGSMFrameSize, inHeader->nFilledLen);
274             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
275             mSignalledError = true;
276         }
277 
278         if (outHeader->nAllocLen < (inHeader->nFilledLen / kMSGSMFrameSize) * 320) {
279             ALOGE("output buffer is not large enough (%d).", outHeader->nAllocLen);
280             android_errorWriteLog(0x534e4554, "27793367");
281             notify(OMX_EventError, OMX_ErrorUndefined, 0, NULL);
282             mSignalledError = true;
283             return;
284         }
285 
286         uint8_t *inputptr = inHeader->pBuffer + inHeader->nOffset;
287 
288         int n = mSignalledError ? 0 : DecodeGSM(mGsm,
289                   reinterpret_cast<int16_t *>(outHeader->pBuffer), inputptr, inHeader->nFilledLen);
290 
291         outHeader->nTimeStamp = inHeader->nTimeStamp;
292         outHeader->nOffset = 0;
293         outHeader->nFilledLen = n * sizeof(int16_t);
294         outHeader->nFlags = 0;
295 
296         if (inHeader->nFlags & OMX_BUFFERFLAG_EOS) {
297             inHeader->nFilledLen = 0;
298         } else {
299             inInfo->mOwnedByUs = false;
300             inQueue.erase(inQueue.begin());
301             inInfo = NULL;
302             notifyEmptyBufferDone(inHeader);
303             inHeader = NULL;
304         }
305 
306         outInfo->mOwnedByUs = false;
307         outQueue.erase(outQueue.begin());
308         outInfo = NULL;
309         notifyFillBufferDone(outHeader);
310         outHeader = NULL;
311     }
312 }
313 
314 
315 // static
DecodeGSM(gsm handle,int16_t * out,uint8_t * in,size_t inSize)316 int SoftGSM::DecodeGSM(gsm handle,
317         int16_t *out, uint8_t *in, size_t inSize) {
318 
319     int ret = 0;
320     while (inSize > 0) {
321         gsm_decode(handle, in, out);
322         in += 33;
323         inSize -= 33;
324         out += 160;
325         ret += 160;
326         gsm_decode(handle, in, out);
327         in += 32;
328         inSize -= 32;
329         out += 160;
330         ret += 160;
331     }
332     return ret;
333 }
334 
onPortFlushCompleted(OMX_U32 portIndex)335 void SoftGSM::onPortFlushCompleted(OMX_U32 portIndex) {
336     if (portIndex == 0) {
337         gsm_destroy(mGsm);
338         mGsm = gsm_create();
339         int msopt = 1;
340         gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
341     }
342 }
343 
onReset()344 void SoftGSM::onReset() {
345     gsm_destroy(mGsm);
346     mGsm = gsm_create();
347     int msopt = 1;
348     gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
349     mSignalledError = false;
350 }
351 
352 
353 
354 
355 }  // namespace android
356 
createSoftOMXComponent(const char * name,const OMX_CALLBACKTYPE * callbacks,OMX_PTR appData,OMX_COMPONENTTYPE ** component)357 android::SoftOMXComponent *createSoftOMXComponent(
358         const char *name, const OMX_CALLBACKTYPE *callbacks,
359         OMX_PTR appData, OMX_COMPONENTTYPE **component) {
360     return new android::SoftGSM(name, callbacks, appData, component);
361 }
362 
363