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