blob: ca43debb8cfc88fcca8b91cbb011d6bfb73fc966 [file] [log] [blame]
Benny Prijono06e62d72008-01-11 09:01:50 +00001/* $Id$ */
2/*
3 * Copyright (C) 2003-2007 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
20 /**
21 * \page page_pjmedia_samples_encdec_c Samples: Encoding and Decoding
22 *
23 * This sample shows how to use codec.
24 *
25 * This file is pjsip-apps/src/samples/encdec.c
26 *
27 * \includelineno encdec.c
28 */
29
30#include <pjlib.h>
31#include <pjmedia.h>
32#include <pjmedia-codec.h>
33
34#define THIS_FILE "encdec.c"
35
36static const char *desc =
37 " encdec \n"
38 " \n"
39 " PURPOSE: \n"
40 " Encode input WAV with a codec, and decode the result to another WAV \n"
41 "\n"
42 "\n"
43 " USAGE: \n"
44 " encdec codec input.wav output.wav \n"
45 "\n"
46 "\n"
47 " where:\n"
48 " codec Set the codec name. \n"
49 " input.wav Set the input WAV filename. \n"
50 " output.wav Set the output WAV filename. \n"
51
52 "\n"
53;
54
Benny Prijono4c5351f2008-01-11 16:30:22 +000055#ifndef HAS_G729_CODEC
56# define HAS_G729_CODEC 0
Benny Prijono06e62d72008-01-11 09:01:50 +000057#endif
58
Benny Prijono4c5351f2008-01-11 16:30:22 +000059#if HAS_G729_CODEC
60#include <keystream_g729ab.h>
61#endif
62
63//#undef PJ_TRACE
64//#define PJ_TRACE 1
65
66#ifndef PJ_TRACE
67# define PJ_TRACE 0
68#endif
69
70#if PJ_TRACE
Benny Prijono06e62d72008-01-11 09:01:50 +000071# define TRACE_(expr) PJ_LOG(4,expr)
72#else
73# define TRACE_(expr)
74#endif
75
76
77static void err(const char *op, pj_status_t status)
78{
79 char errmsg[PJ_ERR_MSG_SIZE];
80 pj_strerror(status, errmsg, sizeof(errmsg));
81 PJ_LOG(3,("", "%s error: %s", op, errmsg));
82}
83
84#define CHECK(op) do { \
85 status = op; \
86 if (status != PJ_SUCCESS) { \
87 err(#op, status); \
88 return status; \
89 } \
90 } \
91 while (0)
92
93static pjmedia_endpt *mept;
94static unsigned file_msec_duration;
95
96static pj_status_t enc_dec_test(const char *codec_id,
97 const char *filein,
98 const char *fileout)
99{
100 pj_pool_t *pool;
101 pjmedia_codec_mgr *cm;
102 pjmedia_codec *codec;
Benny Prijono4c5351f2008-01-11 16:30:22 +0000103 const pjmedia_codec_info *pci;
Benny Prijono06e62d72008-01-11 09:01:50 +0000104 pjmedia_codec_param param;
105 unsigned cnt, samples_per_frame;
106 pj_str_t tmp;
107 pjmedia_port *wavin, *wavout;
Benny Prijono4c5351f2008-01-11 16:30:22 +0000108 unsigned lost_pct;
Benny Prijono06e62d72008-01-11 09:01:50 +0000109 pj_status_t status;
110
Benny Prijono4c5351f2008-01-11 16:30:22 +0000111#define T file_msec_duration/1000, file_msec_duration%1000
112
Benny Prijono06e62d72008-01-11 09:01:50 +0000113 pool = pjmedia_endpt_create_pool(mept, "encdec", 1000, 1000);
114
115 cm = pjmedia_endpt_get_codec_mgr(mept);
116
Benny Prijono4c5351f2008-01-11 16:30:22 +0000117#ifdef LOST_PCT
118 lost_pct = LOST_PCT;
119#else
120 lost_pct = 0;
121#endif
122
Benny Prijono06e62d72008-01-11 09:01:50 +0000123 cnt = 1;
124 CHECK( pjmedia_codec_mgr_find_codecs_by_id(cm, pj_cstr(&tmp, codec_id),
125 &cnt, &pci, NULL) );
126 CHECK( pjmedia_codec_mgr_get_default_param(cm, pci, &param) );
127
128 samples_per_frame = param.info.clock_rate * param.info.frm_ptime / 1000;
129
130 /* Control VAD */
Benny Prijono4c5351f2008-01-11 16:30:22 +0000131 param.setting.vad = 1;
Benny Prijono06e62d72008-01-11 09:01:50 +0000132
133 /* Open wav for reading */
134 CHECK( pjmedia_wav_player_port_create(pool, filein,
135 param.info.frm_ptime,
136 PJMEDIA_FILE_NO_LOOP, 0, &wavin) );
137
138 /* Open wav for writing */
139 CHECK( pjmedia_wav_writer_port_create(pool, fileout,
140 param.info.clock_rate,
141 param.info.channel_cnt,
142 samples_per_frame,
143 16, 0, 0, &wavout) );
144
145 /* Alloc codec */
146 CHECK( pjmedia_codec_mgr_alloc_codec(cm, pci, &codec) );
147 CHECK( codec->op->init(codec, pool) );
148 CHECK( codec->op->open(codec, &param) );
149
150 for (;;) {
151 pjmedia_frame frm_pcm, frm_bit, out_frm, frames[4];
152 pj_int16_t pcmbuf[320];
153 pj_timestamp ts;
154 pj_uint8_t bitstream[160];
155
156 frm_pcm.buf = (char*)pcmbuf;
157 frm_pcm.size = samples_per_frame * 2;
158
159 /* Read from WAV */
160 if (pjmedia_port_get_frame(wavin, &frm_pcm) != PJ_SUCCESS)
161 break;
162 if (frm_pcm.type != PJMEDIA_FRAME_TYPE_AUDIO)
163 break;;
164
Benny Prijono4c5351f2008-01-11 16:30:22 +0000165 /* Update duration */
166 file_msec_duration += samples_per_frame * 1000 /
167 param.info.clock_rate;
168
Benny Prijono06e62d72008-01-11 09:01:50 +0000169 /* Encode */
170 frm_bit.buf = bitstream;
171 frm_bit.size = sizeof(bitstream);
172 CHECK(codec->op->encode(codec, &frm_pcm, sizeof(bitstream), &frm_bit));
173
Benny Prijono4c5351f2008-01-11 16:30:22 +0000174 /* On DTX, write zero frame to wavout to maintain duration */
175 if (frm_bit.size == 0 || frm_bit.type != PJMEDIA_FRAME_TYPE_AUDIO) {
176 out_frm.buf = (char*)pcmbuf;
177 out_frm.size = 160;
178 CHECK( pjmedia_port_put_frame(wavout, &out_frm) );
179 TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u",
180 T, frm_pcm.size, frm_bit.size));
181 continue;
182 }
183
184 /* Simulate jitter buffer bug */
185 if (pci->pt==PJMEDIA_RTP_PT_G729 && frm_bit.size == 2) {
186 TRACE_((THIS_FILE, "%d.%03d G729 SID frame masqueraded", T));
187 frm_bit.size = 10;
188 }
189
Benny Prijono06e62d72008-01-11 09:01:50 +0000190 /* Parse the bitstream (not really necessary for this case
191 * since we always decode 1 frame, but it's still good
192 * for testing)
193 */
194 ts.u64 = 0;
195 cnt = PJ_ARRAY_SIZE(frames);
196 CHECK( codec->op->parse(codec, bitstream, frm_bit.size, &ts, &cnt,
197 frames) );
198 CHECK( (cnt==1 ? PJ_SUCCESS : -1) );
199
Benny Prijono4c5351f2008-01-11 16:30:22 +0000200 /* Decode or simulate packet loss */
Benny Prijono06e62d72008-01-11 09:01:50 +0000201 out_frm.buf = (char*)pcmbuf;
202 out_frm.size = sizeof(pcmbuf);
Benny Prijono4c5351f2008-01-11 16:30:22 +0000203
Benny Prijonoa2687702008-01-12 11:23:02 +0000204 if ((pj_rand() % 100) < (int)lost_pct) {
Benny Prijono4c5351f2008-01-11 16:30:22 +0000205 /* Simulate loss */
206 CHECK( codec->op->recover(codec, sizeof(pcmbuf), &out_frm) );
207 TRACE_((THIS_FILE, "%d.%03d Packet lost", T));
208 } else {
209 /* Decode */
210 CHECK( codec->op->decode(codec, &frames[0], sizeof(pcmbuf),
211 &out_frm) );
212 }
Benny Prijono06e62d72008-01-11 09:01:50 +0000213
214 /* Write to WAV */
215 CHECK( pjmedia_port_put_frame(wavout, &out_frm) );
216
Benny Prijono4c5351f2008-01-11 16:30:22 +0000217 TRACE_((THIS_FILE, "%d.%03d read: %u, enc: %u, dec/write: %u",
218 T, frm_pcm.size, frm_bit.size, out_frm.size));
Benny Prijono06e62d72008-01-11 09:01:50 +0000219 }
220
221 /* Close wavs */
222 pjmedia_port_destroy(wavout);
223 pjmedia_port_destroy(wavin);
224
225 /* Close codec */
226 codec->op->close(codec);
227 pjmedia_codec_mgr_dealloc_codec(cm, codec);
228
229 /* Release pool */
230 pj_pool_release(pool);
231
232 return PJ_SUCCESS;
233}
234
235
236int main(int argc, char *argv[])
237{
238 pj_caching_pool cp;
239 pj_time_val t0, t1;
240 pj_status_t status;
241
242 if (argc != 4) {
243 puts(desc);
244 return 1;
245 }
246
247 CHECK( pj_init() );
248
249 pj_caching_pool_init(&cp, NULL, 0);
250
251 CHECK( pjmedia_endpt_create(&cp.factory, NULL, 1, &mept) );
252
253 /* Register all codecs */
254#if PJMEDIA_HAS_G711_CODEC
255 CHECK( pjmedia_codec_g711_init(mept) );
256#endif
257#if PJMEDIA_HAS_GSM_CODEC
258 CHECK( pjmedia_codec_gsm_init(mept) );
259#endif
260#if PJMEDIA_HAS_ILBC_CODEC
261 CHECK( pjmedia_codec_ilbc_init(mept, 30) );
262#endif
263#if PJMEDIA_HAS_SPEEX_CODEC
264 CHECK( pjmedia_codec_speex_init(mept, 0, 5, 5) );
265#endif
266#if HAS_G729_CODEC
267 CHECK( keystream_g729ab_init(mept) );
268#endif
Benny Prijono7ffd7752008-03-17 14:07:53 +0000269#if PJMEDIA_HAS_G722_CODEC
270 CHECK( pjmedia_codec_g722_init(mept) );
271#endif
Benny Prijono06e62d72008-01-11 09:01:50 +0000272
273 pj_gettimeofday(&t0);
274 status = enc_dec_test(argv[1], argv[2], argv[3]);
275 pj_gettimeofday(&t1);
276 PJ_TIME_VAL_SUB(t1, t0);
277
278 pjmedia_endpt_destroy(mept);
279 pj_caching_pool_destroy(&cp);
280 pj_shutdown();
281
282 if (status == PJ_SUCCESS) {
283 puts("");
284 puts("Success");
285 printf("Duration: %ds.%03d\n", file_msec_duration/1000,
286 file_msec_duration%1000);
Benny Prijono4c5351f2008-01-11 16:30:22 +0000287 printf("Time: %lds.%03ld\n", t1.sec, t1.msec);
Benny Prijono06e62d72008-01-11 09:01:50 +0000288 }
289
290 return 0;
291}
292