• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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