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