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