Add support for ICE/STUN/TURN in res_rtp_asterisk and chan_sip.
[asterisk/asterisk.git] / res / pjproject / tests / pjsua / tools / cmp_wav.c
1 /* $Id$ */
2 /* 
3  * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
4  * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA 
19  */
20 #include <pjmedia.h>
21 #include <pjlib-util.h>
22 #include <pjlib.h>
23 #include <stdio.h>
24 #include <stdlib.h>
25
26 #define app_perror(a,b,c) printf("%s: %s (%d)", a, b, c)
27
28
29 /* For logging purpose. */
30 #define THIS_FILE   "cmp_wav.c"
31 #define BYTES_PER_FRAME     512
32
33 static const char *desc = 
34 " FILE                                                              \n"
35 "                                                                   \n"
36 "  cmp_wav.c                                                        \n"
37 "                                                                   \n"
38 " PURPOSE                                                           \n"
39 "                                                                   \n"
40 "  Compare two WAV files.                                           \n"
41 "                                                                   \n"
42 " USAGE                                                             \n"
43 "                                                                   \n"
44 "  cmp_wav ORIGINAL_WAV DEGRADED_WAV [TIME] [DETAIL]                \n"
45 "                                                                   \n"
46 "  ORIGINAL_WAV     The original WAV file as reference.             \n"
47 "  DEGRADED_WAV     The degraded WAV file.                          \n"
48 "  TIME             Compare only some part of the files             \n"
49 "                   (in ms, since the beginning).                   \n"
50 "                   Specify 0 (default) to compare the whole time.  \n"
51 "  DETAIL           Show detail result, 1 or 0 (default=0, means no)\n"
52 "                                                                   \n"
53 "  Both files must have same clock rate and must contain            \n"
54 "  uncompressed (i.e. 16bit) PCM.                                   \n";
55
56
57 /* Sum of multiplication of corresponding samples in buf1 & buf2 */
58 double sum_mult_sig(pj_int16_t *buf1, pj_int16_t *buf2, unsigned nsamples)
59 {
60     double mag = 0;
61
62     while (nsamples--)
63         mag += (double)*buf1++ * (double)*buf2++;
64
65     return mag;
66 }
67
68
69 /*
70  * main()
71  */
72 int main(int argc, char *argv[])
73 {
74     pj_caching_pool cp;
75     pjmedia_endpt *med_endpt;
76     pj_pool_t *pool;
77     pjmedia_port *file_ori_port;
78     pjmedia_port *file_deg_port;
79     pj_status_t status;
80     unsigned first_nsamples = 0;
81     unsigned samples_compared = 0;
82
83     char buf1[BYTES_PER_FRAME];
84     char buf2[BYTES_PER_FRAME];
85
86     double ref_mag = 0;
87     double deg_mag = 0;
88     double mix_mag = 0;
89
90     int detail = 0;
91     int res_deg, res_mix, res_overall;
92
93     if (argc < 3) {
94         puts("Error: original & degraded filename required");
95         puts(desc);
96         return 1;
97     }
98
99     /* Set log level. */
100     pj_log_set_level(3);
101
102     /* Must init PJLIB first: */
103     status = pj_init();
104     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
105
106     /* Must create a pool factory before we can allocate any memory. */
107     pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
108
109     /* 
110      * Initialize media endpoint.
111      * This will implicitly initialize PJMEDIA too.
112      */
113     status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
114     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
115
116     /* Create memory pool for our file player */
117     pool = pj_pool_create( &cp.factory,     /* pool factory         */
118                            "wav",           /* pool name.           */
119                            4000,            /* init size            */
120                            4000,            /* increment size       */
121                            NULL             /* callback on error    */
122                            );
123
124     /* Create file media port from the original WAV file */
125     status = pjmedia_wav_player_port_create(  pool,     /* memory pool      */
126                                               argv[1],  /* file to play     */
127                                               40,       /* ptime.           */
128                                               PJMEDIA_FILE_NO_LOOP,     /* flags            */
129                                               0,        /* default buffer   */
130                                               &file_ori_port/* returned port    */
131                                               );
132     if (status != PJ_SUCCESS) {
133         app_perror(THIS_FILE, "Unable to use WAV file", status);
134         return 1;
135     }
136
137     /* Create file media port from the degraded WAV file */
138     status = pjmedia_wav_player_port_create(  pool,     /* memory pool      */
139                                               argv[2],  /* file to play     */
140                                               40,       /* ptime.           */
141                                               PJMEDIA_FILE_NO_LOOP,     /* flags            */
142                                               0,        /* default buffer   */
143                                               &file_deg_port/* returned port    */
144                                               );
145     if (status != PJ_SUCCESS) {
146         app_perror(THIS_FILE, "Unable to use WAV file", status);
147         return 1;
148     }
149
150     if (file_ori_port->info.clock_rate != file_deg_port->info.clock_rate) {
151         app_perror(THIS_FILE, "Clock rates must be same.", PJ_EINVAL);
152         return 1;
153     }
154
155     if (argc > 3)
156         first_nsamples = atoi(argv[3]) * file_ori_port->info.clock_rate / 1000;
157
158     if (argc > 4)
159         detail = atoi(argv[4]);
160
161     while (1) {
162         pjmedia_frame f1, f2;
163
164         f1.buf = buf1;
165         f1.size = BYTES_PER_FRAME;
166         f2.buf = buf2;
167         f2.size = BYTES_PER_FRAME;
168
169         status = pjmedia_port_get_frame(file_ori_port, &f1);
170         if (status == PJ_EEOF) {
171             break;
172         } else if (status != PJ_SUCCESS) {
173             app_perror(THIS_FILE, "Error occured while reading file", status);
174             break;
175         }
176         status = pjmedia_port_get_frame(file_deg_port, &f2);
177         if (status == PJ_EEOF) {
178             break;
179         } else if (status != PJ_SUCCESS) {
180             app_perror(THIS_FILE, "Error occured while reading file", status);
181             break;
182         }
183
184         /* Calculate magnitudes */
185         ref_mag += sum_mult_sig(f1.buf, f1.buf, BYTES_PER_FRAME >> 1);
186         deg_mag += sum_mult_sig(f2.buf, f2.buf, BYTES_PER_FRAME >> 1);
187         mix_mag += sum_mult_sig(f1.buf, f2.buf, BYTES_PER_FRAME >> 1);
188
189         samples_compared += BYTES_PER_FRAME >> 1;
190         if (first_nsamples && samples_compared >= first_nsamples)
191             break;
192     }
193
194     /* Degraded magnitude compared to reference magnitude 
195      */
196     res_deg = (int) (deg_mag / ref_mag * 100.0);
197     if (res_deg < 0)
198         res_deg = -1;
199     else if (res_deg >= 81)
200         res_deg = 9;
201     else
202         res_deg = pj_isqrt(res_deg);
203
204     /* Mixed magnitude (don't know what this is actually :D) compared to 
205      * reference magnitude 
206      */
207     res_mix = (int) (mix_mag / ref_mag * 100.0);
208     if (res_mix < 0)
209         res_mix = -1;
210     else if (res_mix >= 81)
211         res_mix = 9;
212     else
213         res_mix = pj_isqrt(res_mix);
214
215     /* Overall score.
216      * If mixed score is -1, then overall score should be -1 as well.
217      * Apply no weighting (1:1) for now.
218      */
219     if (res_mix == -1)
220         res_overall = -1;
221     else
222         res_overall = (res_mix*1 + res_deg*1) / 2;
223
224     if (detail) {
225         printf("Reference = %.0f\n", ref_mag);
226         printf("Degraded  = %.0f\n", deg_mag);
227         printf("Mixed     = %.0f\n", mix_mag);
228
229         printf("\n");
230
231         printf("Score 1   = %d\n", res_deg);
232         printf("Score 2   = %d\n", res_mix);
233
234         printf("\n");
235     }
236
237     printf("Overall   = %d\n", res_overall);
238
239     /* Destroy file port */
240     status = pjmedia_port_destroy( file_ori_port );
241     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
242
243     status = pjmedia_port_destroy( file_deg_port );
244     PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
245
246     /* Release application pool */
247     pj_pool_release( pool );
248
249     /* Destroy media endpoint. */
250     pjmedia_endpt_destroy( med_endpt );
251
252     /* Destroy pool factory */
253     pj_caching_pool_destroy( &cp );
254
255     /* Shutdown PJLIB */
256     pj_shutdown();
257
258
259     /* Done. */
260     return 0;
261 }
262