blob: f774a5e5d7bcf320ba07dd711689c764163ceb3f [file] [log] [blame]
Benny Prijonoa4bf0212006-02-10 15:57:08 +00001/* $Id$ */
2/*
3 * Copyright (C)2003-2006 Benny Prijono <benny@prijono.org>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19#include <pjmedia-codec/gsm.h>
20#include <pjmedia/codec.h>
21#include <pjmedia/errno.h>
22#include <pjmedia/endpoint.h>
Benny Prijono70c68912006-05-19 15:58:13 +000023#include <pjmedia/plc.h>
Benny Prijonof04ffdd2006-02-21 00:11:18 +000024#include <pjmedia/port.h>
Benny Prijono70c68912006-05-19 15:58:13 +000025#include <pjmedia/silencedet.h>
Benny Prijonoa4bf0212006-02-10 15:57:08 +000026#include <pj/assert.h>
27#include <pj/pool.h>
28#include <pj/string.h>
29#include <pj/os.h>
30#include "gsm/gsm.h"
31
Benny Prijono4381efe2006-03-16 14:24:26 +000032/*
33 * Only build this file if PJMEDIA_HAS_GSM_CODEC != 0
34 */
35#if defined(PJMEDIA_HAS_GSM_CODEC) && PJMEDIA_HAS_GSM_CODEC != 0
36
37
Benny Prijonoa4bf0212006-02-10 15:57:08 +000038/* Prototypes for GSM factory */
39static pj_status_t gsm_test_alloc( pjmedia_codec_factory *factory,
40 const pjmedia_codec_info *id );
41static pj_status_t gsm_default_attr( pjmedia_codec_factory *factory,
42 const pjmedia_codec_info *id,
43 pjmedia_codec_param *attr );
44static pj_status_t gsm_enum_codecs( pjmedia_codec_factory *factory,
45 unsigned *count,
46 pjmedia_codec_info codecs[]);
47static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory,
48 const pjmedia_codec_info *id,
49 pjmedia_codec **p_codec);
50static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory,
51 pjmedia_codec *codec );
52
53/* Prototypes for GSM implementation. */
Benny Prijonoa4bf0212006-02-10 15:57:08 +000054static pj_status_t gsm_codec_init( pjmedia_codec *codec,
55 pj_pool_t *pool );
56static pj_status_t gsm_codec_open( pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +000057 pjmedia_codec_param *attr );
Benny Prijonoa4bf0212006-02-10 15:57:08 +000058static pj_status_t gsm_codec_close( pjmedia_codec *codec );
Benny Prijonob94a6ab2006-12-26 21:18:11 +000059static pj_status_t gsm_codec_modify(pjmedia_codec *codec,
60 const pjmedia_codec_param *attr );
Benny Prijono8befd9f2006-05-13 22:46:23 +000061static pj_status_t gsm_codec_parse( pjmedia_codec *codec,
62 void *pkt,
63 pj_size_t pkt_size,
64 const pj_timestamp *ts,
65 unsigned *frame_cnt,
66 pjmedia_frame frames[]);
Benny Prijonoa4bf0212006-02-10 15:57:08 +000067static pj_status_t gsm_codec_encode( pjmedia_codec *codec,
68 const struct pjmedia_frame *input,
69 unsigned output_buf_len,
70 struct pjmedia_frame *output);
71static pj_status_t gsm_codec_decode( pjmedia_codec *codec,
72 const struct pjmedia_frame *input,
73 unsigned output_buf_len,
74 struct pjmedia_frame *output);
Benny Prijono70c68912006-05-19 15:58:13 +000075static pj_status_t gsm_codec_recover(pjmedia_codec *codec,
76 unsigned output_buf_len,
77 struct pjmedia_frame *output);
Benny Prijonoa4bf0212006-02-10 15:57:08 +000078
79/* Definition for GSM codec operations. */
80static pjmedia_codec_op gsm_op =
81{
Benny Prijonoa4bf0212006-02-10 15:57:08 +000082 &gsm_codec_init,
83 &gsm_codec_open,
84 &gsm_codec_close,
Benny Prijonob94a6ab2006-12-26 21:18:11 +000085 &gsm_codec_modify,
Benny Prijono8befd9f2006-05-13 22:46:23 +000086 &gsm_codec_parse,
Benny Prijonoa4bf0212006-02-10 15:57:08 +000087 &gsm_codec_encode,
Benny Prijono70c68912006-05-19 15:58:13 +000088 &gsm_codec_decode,
89 &gsm_codec_recover
Benny Prijonoa4bf0212006-02-10 15:57:08 +000090};
91
92/* Definition for GSM codec factory operations. */
93static pjmedia_codec_factory_op gsm_factory_op =
94{
95 &gsm_test_alloc,
96 &gsm_default_attr,
97 &gsm_enum_codecs,
98 &gsm_alloc_codec,
99 &gsm_dealloc_codec
100};
101
102/* GSM factory */
103static struct gsm_codec_factory
104{
105 pjmedia_codec_factory base;
106 pjmedia_endpt *endpt;
107 pj_pool_t *pool;
108 pj_mutex_t *mutex;
109 pjmedia_codec codec_list;
110} gsm_codec_factory;
111
Benny Prijono70c68912006-05-19 15:58:13 +0000112
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000113/* GSM codec private data. */
Benny Prijonof93895c2006-03-05 11:50:53 +0000114struct gsm_data
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000115{
Benny Prijono70c68912006-05-19 15:58:13 +0000116 void *encoder;
117 void *decoder;
118 pj_bool_t plc_enabled;
119 pjmedia_plc *plc;
120 pj_bool_t vad_enabled;
121 pjmedia_silence_det *vad;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000122};
123
124
125
126/*
127 * Initialize and register GSM codec factory to pjmedia endpoint.
128 */
129PJ_DEF(pj_status_t) pjmedia_codec_gsm_init( pjmedia_endpt *endpt )
130{
131 pjmedia_codec_mgr *codec_mgr;
132 pj_status_t status;
133
134 if (gsm_codec_factory.pool != NULL)
135 return PJ_SUCCESS;
136
137 /* Create GSM codec factory. */
138 gsm_codec_factory.base.op = &gsm_factory_op;
139 gsm_codec_factory.base.factory_data = NULL;
140 gsm_codec_factory.endpt = endpt;
141
142 gsm_codec_factory.pool = pjmedia_endpt_create_pool(endpt, "gsm", 4000,
143 4000);
144 if (!gsm_codec_factory.pool)
145 return PJ_ENOMEM;
146
147 pj_list_init(&gsm_codec_factory.codec_list);
148
149 /* Create mutex. */
150 status = pj_mutex_create_simple(gsm_codec_factory.pool, "gsm",
151 &gsm_codec_factory.mutex);
152 if (status != PJ_SUCCESS)
153 goto on_error;
154
155 /* Get the codec manager. */
156 codec_mgr = pjmedia_endpt_get_codec_mgr(endpt);
157 if (!codec_mgr) {
158 status = PJ_EINVALIDOP;
159 goto on_error;
160 }
161
162 /* Register codec factory to endpoint. */
163 status = pjmedia_codec_mgr_register_factory(codec_mgr,
164 &gsm_codec_factory.base);
165 if (status != PJ_SUCCESS)
166 goto on_error;
167
168 /* Done. */
169 return PJ_SUCCESS;
170
171on_error:
172 pj_pool_release(gsm_codec_factory.pool);
173 gsm_codec_factory.pool = NULL;
174 return status;
175}
176
177
178
179/*
180 * Unregister GSM codec factory from pjmedia endpoint and deinitialize
181 * the GSM codec library.
182 */
183PJ_DEF(pj_status_t) pjmedia_codec_gsm_deinit(void)
184{
185 pjmedia_codec_mgr *codec_mgr;
186 pj_status_t status;
187
188 if (gsm_codec_factory.pool == NULL)
189 return PJ_SUCCESS;
190
191 /* We don't want to deinit if there's outstanding codec. */
192 pj_mutex_lock(gsm_codec_factory.mutex);
193 if (!pj_list_empty(&gsm_codec_factory.codec_list)) {
194 pj_mutex_unlock(gsm_codec_factory.mutex);
195 return PJ_EBUSY;
196 }
197
198 /* Get the codec manager. */
199 codec_mgr = pjmedia_endpt_get_codec_mgr(gsm_codec_factory.endpt);
200 if (!codec_mgr) {
201 pj_pool_release(gsm_codec_factory.pool);
202 gsm_codec_factory.pool = NULL;
203 return PJ_EINVALIDOP;
204 }
205
206 /* Unregister GSM codec factory. */
207 status = pjmedia_codec_mgr_unregister_factory(codec_mgr,
208 &gsm_codec_factory.base);
209
210 /* Destroy mutex. */
211 pj_mutex_destroy(gsm_codec_factory.mutex);
212
213 /* Destroy pool. */
214 pj_pool_release(gsm_codec_factory.pool);
215 gsm_codec_factory.pool = NULL;
216
217 return status;
218}
219
220/*
221 * Check if factory can allocate the specified codec.
222 */
223static pj_status_t gsm_test_alloc( pjmedia_codec_factory *factory,
224 const pjmedia_codec_info *info )
225{
226 PJ_UNUSED_ARG(factory);
227
228 /* Check payload type. */
229 if (info->pt != PJMEDIA_RTP_PT_GSM)
230 return PJMEDIA_CODEC_EUNSUP;
231
232 /* Ignore the rest, since it's static payload type. */
233
234 return PJ_SUCCESS;
235}
236
237/*
238 * Generate default attribute.
239 */
240static pj_status_t gsm_default_attr (pjmedia_codec_factory *factory,
241 const pjmedia_codec_info *id,
242 pjmedia_codec_param *attr )
243{
244 PJ_UNUSED_ARG(factory);
245 PJ_UNUSED_ARG(id);
246
Benny Prijonoac623b32006-07-03 15:19:31 +0000247 pj_bzero(attr, sizeof(pjmedia_codec_param));
Benny Prijono8befd9f2006-05-13 22:46:23 +0000248 attr->info.clock_rate = 8000;
249 attr->info.channel_cnt = 1;
250 attr->info.avg_bps = 13200;
251 attr->info.pcm_bits_per_sample = 16;
252 attr->info.frm_ptime = 20;
253 attr->info.pt = PJMEDIA_RTP_PT_GSM;
254
255 attr->setting.frm_per_pkt = 1;
Benny Prijono70c68912006-05-19 15:58:13 +0000256 attr->setting.vad = 1;
257 attr->setting.plc = 1;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000258
Benny Prijono70c68912006-05-19 15:58:13 +0000259 /* Default all other flag bits disabled. */
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000260
261 return PJ_SUCCESS;
262}
263
264/*
265 * Enum codecs supported by this factory (i.e. only GSM!).
266 */
267static pj_status_t gsm_enum_codecs(pjmedia_codec_factory *factory,
268 unsigned *count,
269 pjmedia_codec_info codecs[])
270{
271 PJ_UNUSED_ARG(factory);
272 PJ_ASSERT_RETURN(codecs && *count > 0, PJ_EINVAL);
273
Benny Prijonoac623b32006-07-03 15:19:31 +0000274 pj_bzero(&codecs[0], sizeof(pjmedia_codec_info));
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000275 codecs[0].encoding_name = pj_str("GSM");
276 codecs[0].pt = PJMEDIA_RTP_PT_GSM;
277 codecs[0].type = PJMEDIA_TYPE_AUDIO;
Benny Prijonoa837c302006-04-27 22:36:40 +0000278 codecs[0].clock_rate = 8000;
279 codecs[0].channel_cnt = 1;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000280
281 *count = 1;
282
283 return PJ_SUCCESS;
284}
285
286/*
287 * Allocate a new GSM codec instance.
288 */
289static pj_status_t gsm_alloc_codec( pjmedia_codec_factory *factory,
290 const pjmedia_codec_info *id,
291 pjmedia_codec **p_codec)
292{
293 pjmedia_codec *codec;
Benny Prijonof93895c2006-03-05 11:50:53 +0000294 struct gsm_data *gsm_data;
Benny Prijono70c68912006-05-19 15:58:13 +0000295 pj_status_t status;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000296
297 PJ_ASSERT_RETURN(factory && id && p_codec, PJ_EINVAL);
298 PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
299
300
301 pj_mutex_lock(gsm_codec_factory.mutex);
302
303 /* Get free nodes, if any. */
304 if (!pj_list_empty(&gsm_codec_factory.codec_list)) {
305 codec = gsm_codec_factory.codec_list.next;
306 pj_list_erase(codec);
307 } else {
308 codec = pj_pool_zalloc(gsm_codec_factory.pool,
309 sizeof(pjmedia_codec));
310 PJ_ASSERT_RETURN(codec != NULL, PJ_ENOMEM);
Benny Prijonof80b1bf2006-02-19 02:24:27 +0000311 codec->op = &gsm_op;
312 codec->factory = factory;
Benny Prijonof93895c2006-03-05 11:50:53 +0000313
314 gsm_data = pj_pool_zalloc(gsm_codec_factory.pool,
315 sizeof(struct gsm_data));
316 codec->codec_data = gsm_data;
Benny Prijono70c68912006-05-19 15:58:13 +0000317
318 /* Create PLC */
319 status = pjmedia_plc_create(gsm_codec_factory.pool, 8000,
320 160, 0, &gsm_data->plc);
321 if (status != PJ_SUCCESS) {
322 pj_mutex_unlock(gsm_codec_factory.mutex);
323 return status;
324 }
325
326 /* Create silence detector */
327 status = pjmedia_silence_det_create(gsm_codec_factory.pool,
328 8000, 160,
329 &gsm_data->vad);
330 if (status != PJ_SUCCESS) {
331 pj_mutex_unlock(gsm_codec_factory.mutex);
332 return status;
333 }
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000334 }
335
336 pj_mutex_unlock(gsm_codec_factory.mutex);
337
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000338 *p_codec = codec;
339 return PJ_SUCCESS;
340}
341
342/*
343 * Free codec.
344 */
345static pj_status_t gsm_dealloc_codec( pjmedia_codec_factory *factory,
346 pjmedia_codec *codec )
347{
Benny Prijonof93895c2006-03-05 11:50:53 +0000348 struct gsm_data *gsm_data;
Benny Prijono87445bc2006-07-26 11:23:07 +0000349 pj_int16_t frame[160];
350 int i;
Benny Prijonof93895c2006-03-05 11:50:53 +0000351
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000352 PJ_ASSERT_RETURN(factory && codec, PJ_EINVAL);
353 PJ_ASSERT_RETURN(factory == &gsm_codec_factory.base, PJ_EINVAL);
354
Benny Prijonof93895c2006-03-05 11:50:53 +0000355 gsm_data = codec->codec_data;
356
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000357 /* Close codec, if it's not closed. */
Benny Prijonof93895c2006-03-05 11:50:53 +0000358 gsm_codec_close(codec);
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000359
Benny Prijono87445bc2006-07-26 11:23:07 +0000360 /* Clear left samples in the PLC, since codec+plc will be reused
361 * next time.
362 */
363 for (i=0; i<2; ++i) {
364 pjmedia_zero_samples(frame, PJ_ARRAY_SIZE(frame));
365 pjmedia_plc_save(gsm_data->plc, frame);
366 }
367
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000368 /* Put in the free list. */
369 pj_mutex_lock(gsm_codec_factory.mutex);
370 pj_list_push_front(&gsm_codec_factory.codec_list, codec);
371 pj_mutex_unlock(gsm_codec_factory.mutex);
372
373 return PJ_SUCCESS;
374}
375
376/*
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000377 * Init codec.
378 */
379static pj_status_t gsm_codec_init( pjmedia_codec *codec,
380 pj_pool_t *pool )
381{
382 PJ_UNUSED_ARG(codec);
383 PJ_UNUSED_ARG(pool);
384 return PJ_SUCCESS;
385}
386
387/*
388 * Open codec.
389 */
390static pj_status_t gsm_codec_open( pjmedia_codec *codec,
Benny Prijono6865a3f2006-12-30 02:46:57 +0000391 pjmedia_codec_param *attr )
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000392{
Benny Prijonof93895c2006-03-05 11:50:53 +0000393 struct gsm_data *gsm_data = codec->codec_data;
394
395 pj_assert(gsm_data != NULL);
396 pj_assert(gsm_data->encoder == NULL && gsm_data->decoder == NULL);
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000397
Benny Prijonof93895c2006-03-05 11:50:53 +0000398 gsm_data->encoder = gsm_create();
399 if (!gsm_data->encoder)
400 return PJMEDIA_CODEC_EFAILED;
401
402 gsm_data->decoder = gsm_create();
403 if (!gsm_data->decoder)
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000404 return PJMEDIA_CODEC_EFAILED;
405
Benny Prijono70c68912006-05-19 15:58:13 +0000406 gsm_data->vad_enabled = (attr->setting.vad != 0);
407 gsm_data->plc_enabled = (attr->setting.plc != 0);
408
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000409 return PJ_SUCCESS;
410}
411
412/*
413 * Close codec.
414 */
415static pj_status_t gsm_codec_close( pjmedia_codec *codec )
416{
Benny Prijonof93895c2006-03-05 11:50:53 +0000417 struct gsm_data *gsm_data = codec->codec_data;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000418
Benny Prijonof93895c2006-03-05 11:50:53 +0000419 pj_assert(gsm_data != NULL);
420
421 if (gsm_data->encoder) {
422 gsm_destroy(gsm_data->encoder);
423 gsm_data->encoder = NULL;
424 }
425 if (gsm_data->decoder) {
426 gsm_destroy(gsm_data->decoder);
427 gsm_data->decoder = NULL;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000428 }
429
430 return PJ_SUCCESS;
431}
432
433
434/*
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000435 * Modify codec settings.
436 */
437static pj_status_t gsm_codec_modify(pjmedia_codec *codec,
438 const pjmedia_codec_param *attr )
439{
440 struct gsm_data *gsm_data = codec->codec_data;
441
442 pj_assert(gsm_data != NULL);
Benny Prijono6865a3f2006-12-30 02:46:57 +0000443 pj_assert(gsm_data->encoder != NULL && gsm_data->decoder != NULL);
Benny Prijonob94a6ab2006-12-26 21:18:11 +0000444
445 gsm_data->vad_enabled = (attr->setting.vad != 0);
446 gsm_data->plc_enabled = (attr->setting.plc != 0);
447
448 return PJ_SUCCESS;
449}
450
451
452/*
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000453 * Get frames in the packet.
454 */
Benny Prijono8befd9f2006-05-13 22:46:23 +0000455static pj_status_t gsm_codec_parse( pjmedia_codec *codec,
456 void *pkt,
457 pj_size_t pkt_size,
458 const pj_timestamp *ts,
459 unsigned *frame_cnt,
460 pjmedia_frame frames[])
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000461{
462 unsigned count = 0;
463
464 PJ_UNUSED_ARG(codec);
465
466 PJ_ASSERT_RETURN(frame_cnt, PJ_EINVAL);
467
468 while (pkt_size >= 33 && count < *frame_cnt) {
Benny Prijono8befd9f2006-05-13 22:46:23 +0000469 frames[count].type = PJMEDIA_FRAME_TYPE_AUDIO;
470 frames[count].buf = pkt;
471 frames[count].size = 33;
472 frames[count].timestamp.u64 = ts->u64 + count * 160;
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000473
474 pkt = ((char*)pkt) + 33;
475 pkt_size -= 33;
476
477 ++count;
478 }
479
480 *frame_cnt = count;
481 return PJ_SUCCESS;
482}
483
484/*
485 * Encode frame.
486 */
487static pj_status_t gsm_codec_encode( pjmedia_codec *codec,
488 const struct pjmedia_frame *input,
489 unsigned output_buf_len,
490 struct pjmedia_frame *output)
491{
Benny Prijonof93895c2006-03-05 11:50:53 +0000492 struct gsm_data *gsm_data = codec->codec_data;
493
494 pj_assert(gsm_data != NULL);
495 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000496
497 if (output_buf_len < 33)
498 return PJMEDIA_CODEC_EFRMTOOSHORT;
499
500 if (input->size < 320)
501 return PJMEDIA_CODEC_EPCMTOOSHORT;
502
Benny Prijono70c68912006-05-19 15:58:13 +0000503 /* Detect silence */
504 if (gsm_data->vad_enabled) {
505 pj_bool_t is_silence;
506
507 is_silence = pjmedia_silence_det_detect(gsm_data->vad,
508 input->buf,
509 input->size / 2,
510 NULL);
511 if (is_silence) {
512 output->type = PJMEDIA_FRAME_TYPE_NONE;
513 output->buf = NULL;
514 output->size = 0;
515 output->timestamp.u64 = input->timestamp.u64;
516 return PJ_SUCCESS;
517 }
518 }
519
520 /* Encode */
Benny Prijonof93895c2006-03-05 11:50:53 +0000521 gsm_encode(gsm_data->encoder, (short*)input->buf,
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000522 (unsigned char*)output->buf);
523
524 output->size = 33;
525 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
526
527 return PJ_SUCCESS;
528}
529
530/*
531 * Decode frame.
532 */
533static pj_status_t gsm_codec_decode( pjmedia_codec *codec,
534 const struct pjmedia_frame *input,
535 unsigned output_buf_len,
536 struct pjmedia_frame *output)
537{
Benny Prijonof93895c2006-03-05 11:50:53 +0000538 struct gsm_data *gsm_data = codec->codec_data;
539
540 pj_assert(gsm_data != NULL);
541 PJ_ASSERT_RETURN(input && output, PJ_EINVAL);
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000542
543 if (output_buf_len < 320)
544 return PJMEDIA_CODEC_EPCMTOOSHORT;
545
546 if (input->size < 33)
547 return PJMEDIA_CODEC_EFRMTOOSHORT;
548
Benny Prijonof93895c2006-03-05 11:50:53 +0000549 gsm_decode(gsm_data->decoder,
Benny Prijonof80b1bf2006-02-19 02:24:27 +0000550 (unsigned char*)input->buf,
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000551 (short*)output->buf);
552
553 output->size = 320;
554 output->type = PJMEDIA_FRAME_TYPE_AUDIO;
555
Benny Prijono70c68912006-05-19 15:58:13 +0000556 if (gsm_data->plc_enabled)
557 pjmedia_plc_save( gsm_data->plc, output->buf);
558
559 return PJ_SUCCESS;
560}
561
562
563/*
564 * Recover lost frame.
565 */
566static pj_status_t gsm_codec_recover(pjmedia_codec *codec,
567 unsigned output_buf_len,
568 struct pjmedia_frame *output)
569{
570 struct gsm_data *gsm_data = codec->codec_data;
571
572 PJ_ASSERT_RETURN(gsm_data->plc_enabled, PJ_EINVALIDOP);
573
574 PJ_ASSERT_RETURN(output_buf_len >= 320, PJMEDIA_CODEC_EPCMTOOSHORT);
575
576 pjmedia_plc_generate(gsm_data->plc, output->buf);
577 output->size = 320;
578
Benny Prijonoa4bf0212006-02-10 15:57:08 +0000579 return PJ_SUCCESS;
580}
Benny Prijono4381efe2006-03-16 14:24:26 +0000581
582
583#endif /* PJMEDIA_HAS_GSM_CODEC */
584