1 /*
2 * Copyright (C) 2018 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 "C2SoftGsmDec"
19 #include <log/log.h>
20
21 #include <media/stagefright/foundation/MediaDefs.h>
22
23 #include <C2PlatformSupport.h>
24 #include <SimpleC2Interface.h>
25
26 #include "C2SoftGsmDec.h"
27
28 namespace android {
29
30 namespace {
31
32 constexpr char COMPONENT_NAME[] = "c2.android.gsm.decoder";
33
34 } // namespace
35
36 class C2SoftGsmDec::IntfImpl : public SimpleInterface<void>::BaseParams {
37 public:
IntfImpl(const std::shared_ptr<C2ReflectorHelper> & helper)38 explicit IntfImpl(const std::shared_ptr<C2ReflectorHelper> &helper)
39 : SimpleInterface<void>::BaseParams(
40 helper,
41 COMPONENT_NAME,
42 C2Component::KIND_DECODER,
43 C2Component::DOMAIN_AUDIO,
44 MEDIA_MIMETYPE_AUDIO_MSGSM) {
45 noPrivateBuffers();
46 noInputReferences();
47 noOutputReferences();
48 noInputLatency();
49 noTimeStretch();
50 setDerivedInstance(this);
51
52 addParameter(
53 DefineParam(mAttrib, C2_PARAMKEY_COMPONENT_ATTRIBUTES)
54 .withConstValue(new C2ComponentAttributesSetting(
55 C2Component::ATTRIB_IS_TEMPORAL))
56 .build());
57
58 addParameter(
59 DefineParam(mSampleRate, C2_PARAMKEY_SAMPLE_RATE)
60 .withDefault(new C2StreamSampleRateInfo::output(0u, 8000))
61 .withFields({C2F(mSampleRate, value).equalTo(8000)})
62 .withSetter((Setter<decltype(*mSampleRate)>::StrictValueWithNoDeps))
63 .build());
64
65 addParameter(
66 DefineParam(mChannelCount, C2_PARAMKEY_CHANNEL_COUNT)
67 .withDefault(new C2StreamChannelCountInfo::output(0u, 1))
68 .withFields({C2F(mChannelCount, value).equalTo(1)})
69 .withSetter(Setter<decltype(*mChannelCount)>::StrictValueWithNoDeps)
70 .build());
71
72 addParameter(
73 DefineParam(mBitrate, C2_PARAMKEY_BITRATE)
74 .withDefault(new C2StreamBitrateInfo::input(0u, 13200))
75 .withFields({C2F(mBitrate, value).equalTo(13200)})
76 .withSetter(Setter<decltype(*mBitrate)>::NonStrictValueWithNoDeps)
77 .build());
78
79 addParameter(
80 DefineParam(mInputMaxBufSize, C2_PARAMKEY_INPUT_MAX_BUFFER_SIZE)
81 .withConstValue(new C2StreamMaxBufferSizeInfo::input(0u, 1024 / MSGSM_IN_FRM_SZ * MSGSM_IN_FRM_SZ))
82 .build());
83 }
84
85 private:
86 std::shared_ptr<C2StreamSampleRateInfo::output> mSampleRate;
87 std::shared_ptr<C2StreamChannelCountInfo::output> mChannelCount;
88 std::shared_ptr<C2StreamBitrateInfo::input> mBitrate;
89 std::shared_ptr<C2StreamMaxBufferSizeInfo::input> mInputMaxBufSize;
90 };
91
C2SoftGsmDec(const char * name,c2_node_id_t id,const std::shared_ptr<IntfImpl> & intfImpl)92 C2SoftGsmDec::C2SoftGsmDec(const char *name, c2_node_id_t id,
93 const std::shared_ptr<IntfImpl>& intfImpl)
94 : SimpleC2Component(
95 std::make_shared<SimpleInterface<IntfImpl>>(name, id, intfImpl)),
96 mIntf(intfImpl),
97 mGsm(nullptr) {
98 }
99
C2SoftGsmDec(const char * name,c2_node_id_t id,const std::shared_ptr<C2ReflectorHelper> & helper)100 C2SoftGsmDec::C2SoftGsmDec(const char *name, c2_node_id_t id,
101 const std::shared_ptr<C2ReflectorHelper>& helper)
102 : C2SoftGsmDec(name, id, std::make_shared<IntfImpl>(helper)) {
103 }
104
~C2SoftGsmDec()105 C2SoftGsmDec::~C2SoftGsmDec() {
106 onRelease();
107 }
108
onInit()109 c2_status_t C2SoftGsmDec::onInit() {
110 if (!mGsm) mGsm = gsm_create();
111 if (!mGsm) return C2_NO_MEMORY;
112 int msopt = 1;
113 (void)gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
114 mSignalledError = false;
115 mSignalledEos = false;
116 return C2_OK;
117 }
118
onStop()119 c2_status_t C2SoftGsmDec::onStop() {
120 if (mGsm) {
121 gsm_destroy(mGsm);
122 mGsm = nullptr;
123 }
124 if (!mGsm) mGsm = gsm_create();
125 if (!mGsm) return C2_NO_MEMORY;
126 int msopt = 1;
127 (void)gsm_option(mGsm, GSM_OPT_WAV49, &msopt);
128 mSignalledError = false;
129 mSignalledEos = false;
130 return C2_OK;
131 }
132
onReset()133 void C2SoftGsmDec::onReset() {
134 (void)onStop();
135 }
136
onRelease()137 void C2SoftGsmDec::onRelease() {
138 if (mGsm) {
139 gsm_destroy(mGsm);
140 mGsm = nullptr;
141 }
142 }
143
onFlush_sm()144 c2_status_t C2SoftGsmDec::onFlush_sm() {
145 return onStop();
146 }
147
decodeGSM(gsm handle,int16_t * out,size_t outCapacity,uint8_t * in,size_t inSize)148 static size_t decodeGSM(gsm handle, int16_t *out, size_t outCapacity,
149 uint8_t *in, size_t inSize) {
150 size_t outSize = 0;
151
152 if (inSize % MSGSM_IN_FRM_SZ == 0
153 && (inSize / MSGSM_IN_FRM_SZ * MSGSM_OUT_FRM_SZ * sizeof(*out)
154 <= outCapacity)) {
155 while (inSize > 0) {
156 gsm_decode(handle, in, out);
157 in += FRGSM_IN_FRM_SZ;
158 inSize -= FRGSM_IN_FRM_SZ;
159 out += FRGSM_OUT_FRM_SZ;
160 outSize += FRGSM_OUT_FRM_SZ;
161
162 gsm_decode(handle, in, out);
163 in += FRGSM_IN_FRM_SZ_MINUS_1;
164 inSize -= FRGSM_IN_FRM_SZ_MINUS_1;
165 out += FRGSM_OUT_FRM_SZ;
166 outSize += FRGSM_OUT_FRM_SZ;
167 }
168 }
169
170 return outSize * sizeof(int16_t);
171 }
172
process(const std::unique_ptr<C2Work> & work,const std::shared_ptr<C2BlockPool> & pool)173 void C2SoftGsmDec::process(
174 const std::unique_ptr<C2Work> &work,
175 const std::shared_ptr<C2BlockPool> &pool) {
176 // Initialize output work
177 work->result = C2_OK;
178 work->workletsProcessed = 1u;
179 work->worklets.front()->output.flags = work->input.flags;
180
181 if (mSignalledError || mSignalledEos) {
182 work->result = C2_BAD_VALUE;
183 return;
184 }
185
186 bool eos = ((work->input.flags & C2FrameData::FLAG_END_OF_STREAM) != 0);
187 C2ReadView rView = mDummyReadView;
188 size_t inOffset = 0u;
189 size_t inSize = 0u;
190 if (!work->input.buffers.empty()) {
191 rView = work->input.buffers[0]->data().linearBlocks().front().map().get();
192 inSize = rView.capacity();
193 if (inSize && rView.error()) {
194 ALOGE("read view map failed %d", rView.error());
195 work->result = rView.error();
196 return;
197 }
198 }
199
200 if (inSize == 0) {
201 work->worklets.front()->output.flags = work->input.flags;
202 work->worklets.front()->output.buffers.clear();
203 work->worklets.front()->output.ordinal = work->input.ordinal;
204 if (eos) {
205 mSignalledEos = true;
206 ALOGV("signalled EOS");
207 }
208 return;
209 }
210 ALOGV("in buffer attr. size %zu timestamp %d frameindex %d", inSize,
211 (int)work->input.ordinal.timestamp.peeku(), (int)work->input.ordinal.frameIndex.peeku());
212
213 size_t outCapacity = (inSize / MSGSM_IN_FRM_SZ ) * MSGSM_OUT_FRM_SZ * sizeof(int16_t);
214 std::shared_ptr<C2LinearBlock> block;
215 C2MemoryUsage usage = { C2MemoryUsage::CPU_READ, C2MemoryUsage::CPU_WRITE };
216 c2_status_t err = pool->fetchLinearBlock(outCapacity, usage, &block);
217 if (err != C2_OK) {
218 ALOGE("fetchLinearBlock for Output failed with status %d", err);
219 work->result = C2_NO_MEMORY;
220 return;
221 }
222 C2WriteView wView = block->map().get();
223 if (wView.error()) {
224 ALOGE("write view map failed %d", wView.error());
225 work->result = wView.error();
226 return;
227 }
228
229 int16_t *output = reinterpret_cast<int16_t *>(wView.data());
230 uint8_t *input = const_cast<uint8_t *>(rView.data() + inOffset);
231 size_t outSize = decodeGSM(mGsm, output, outCapacity, input, inSize);
232 if (!outSize) {
233 ALOGE("encountered improper insize or outsize");
234 mSignalledError = true;
235 work->result = C2_CORRUPTED;
236 return;
237 }
238 ALOGV("out buffer attr. size %zu", outSize);
239 work->worklets.front()->output.flags = work->input.flags;
240 work->worklets.front()->output.buffers.clear();
241 work->worklets.front()->output.buffers.push_back(createLinearBuffer(block, 0, outSize));
242 work->worklets.front()->output.ordinal = work->input.ordinal;
243 if (eos) {
244 mSignalledEos = true;
245 ALOGV("signalled EOS");
246 }
247 }
248
drain(uint32_t drainMode,const std::shared_ptr<C2BlockPool> & pool)249 c2_status_t C2SoftGsmDec::drain(
250 uint32_t drainMode,
251 const std::shared_ptr<C2BlockPool> &pool) {
252 (void) pool;
253 if (drainMode == NO_DRAIN) {
254 ALOGW("drain with NO_DRAIN: no-op");
255 return C2_OK;
256 }
257 if (drainMode == DRAIN_CHAIN) {
258 ALOGW("DRAIN_CHAIN not supported");
259 return C2_OMITTED;
260 }
261
262 return C2_OK;
263 }
264
265 class C2SoftGSMDecFactory : public C2ComponentFactory {
266 public:
C2SoftGSMDecFactory()267 C2SoftGSMDecFactory() : mHelper(std::static_pointer_cast<C2ReflectorHelper>(
268 GetCodec2PlatformComponentStore()->getParamReflector())) {
269 }
270
createComponent(c2_node_id_t id,std::shared_ptr<C2Component> * const component,std::function<void (C2Component *)> deleter)271 virtual c2_status_t createComponent(
272 c2_node_id_t id,
273 std::shared_ptr<C2Component>* const component,
274 std::function<void(C2Component*)> deleter) override {
275 *component = std::shared_ptr<C2Component>(
276 new C2SoftGsmDec(COMPONENT_NAME,
277 id,
278 std::make_shared<C2SoftGsmDec::IntfImpl>(mHelper)),
279 deleter);
280 return C2_OK;
281 }
282
createInterface(c2_node_id_t id,std::shared_ptr<C2ComponentInterface> * const interface,std::function<void (C2ComponentInterface *)> deleter)283 virtual c2_status_t createInterface(
284 c2_node_id_t id,
285 std::shared_ptr<C2ComponentInterface>* const interface,
286 std::function<void(C2ComponentInterface*)> deleter) override {
287 *interface = std::shared_ptr<C2ComponentInterface>(
288 new SimpleInterface<C2SoftGsmDec::IntfImpl>(
289 COMPONENT_NAME, id, std::make_shared<C2SoftGsmDec::IntfImpl>(mHelper)),
290 deleter);
291 return C2_OK;
292 }
293
294 virtual ~C2SoftGSMDecFactory() override = default;
295
296 private:
297 std::shared_ptr<C2ReflectorHelper> mHelper;
298 };
299
300 } // namespace android
301
302 __attribute__((cfi_canonical_jump_table))
CreateCodec2Factory()303 extern "C" ::C2ComponentFactory* CreateCodec2Factory() {
304 ALOGV("in %s", __func__);
305 return new ::android::C2SoftGSMDecFactory();
306 }
307
308 __attribute__((cfi_canonical_jump_table))
DestroyCodec2Factory(::C2ComponentFactory * factory)309 extern "C" void DestroyCodec2Factory(::C2ComponentFactory* factory) {
310 ALOGV("in %s", __func__);
311 delete factory;
312 }
313