blob: 90c1721635bb63117ad80536abbe39e54b88543c [file] [log] [blame]
Benny Prijono844653c2008-12-23 17:27:53 +00001/* $Id$ */
Benny Prijono9183c032008-07-28 14:37:47 +00002/*
Benny Prijono844653c2008-12-23 17:27:53 +00003 * Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
Benny Prijono9183c032008-07-28 14:37:47 +00004 * 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
21/* See http://trac.pjsip.org/repos/wiki/MeasuringSoundLatency on
22 * how to use this program.
23 */
24
25#include <pjmedia.h>
26#include <pjlib.h>
27
28#include <stdio.h>
29
30#define THIS_FILE "lacency.c"
31
32
33/* Util to display the error message for the specified error code */
34static int app_perror( const char *sender, const char *title,
35 pj_status_t status)
36{
37 char errmsg[PJ_ERR_MSG_SIZE];
38
39 PJ_UNUSED_ARG(sender);
40
41 pj_strerror(status, errmsg, sizeof(errmsg));
42
43 printf("%s: %s [code=%d]\n", title, errmsg, status);
44 return 1;
45}
46
47/*
48 * Find out latency
49 */
50static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
51{
52 pjmedia_frame frm;
53 short *buf;
54 unsigned i, samples_per_frame, read, len;
55 unsigned start_pos;
56 pj_status_t status;
57
58 unsigned lat_sum = 0,
59 lat_cnt = 0,
60 lat_min = 10000,
61 lat_max = 0;
62
63 samples_per_frame = wav->info.samples_per_frame;
64 frm.buf = pj_pool_alloc(pool, samples_per_frame * 2);
65 frm.size = samples_per_frame * 2;
66 len = pjmedia_wav_player_get_len(wav);
67 buf = pj_pool_alloc(pool, len + samples_per_frame);
68
69 read = 0;
70 while (read < len/2) {
71 status = pjmedia_port_get_frame(wav, &frm);
72 if (status != PJ_SUCCESS)
73 break;
74
75 pjmedia_copy_samples(buf+read, (short*)frm.buf, samples_per_frame);
76 read += samples_per_frame;
77 }
78
79 if (read < 2 * wav->info.clock_rate) {
80 puts("Error: too short");
81 return -1;
82 }
83
84 start_pos = 0;
85 while (start_pos < len/2 - wav->info.clock_rate) {
86 int max_signal = 0;
87 unsigned max_signal_pos = start_pos;
88 unsigned max_echo_pos = 0;
89 unsigned pos;
90 unsigned lat;
91
92 /* Get the largest signal in the next 0.7s */
93 for (i=start_pos; i<start_pos + wav->info.clock_rate * 700 / 1000; ++i) {
94 if (abs(buf[i]) > max_signal) {
95 max_signal = abs(buf[i]);
96 max_signal_pos = i;
97 }
98 }
99
100 /* Advance 10ms from max_signal_pos */
101 pos = max_signal_pos + 10 * wav->info.clock_rate / 1000;
102
103 /* Get the largest signal in the next 500ms */
104 max_signal = 0;
105 max_echo_pos = pos;
106 for (i=pos; i<pos+wav->info.clock_rate/2; ++i) {
107 if (abs(buf[i]) > max_signal) {
108 max_signal = abs(buf[i]);
109 max_echo_pos = i;
110 }
111 }
112
113 lat = (max_echo_pos - max_signal_pos) * 1000 / wav->info.clock_rate;
114
115#if 0
116 printf("Latency = %u\n", lat);
117#endif
118
119 lat_sum += lat;
120 lat_cnt++;
121 if (lat < lat_min)
122 lat_min = lat;
123 if (lat > lat_max)
124 lat_max = lat;
125
126 /* Advance next loop */
127 start_pos += wav->info.clock_rate;
128 }
129
130 printf("Latency average = %u\n", lat_sum / lat_cnt);
131 printf("Latency minimum = %u\n", lat_min);
132 printf("Latency maximum = %u\n", lat_max);
133 printf("Number of data = %u\n", lat_cnt);
134 return 0;
135}
136
137
138/*
139 * main()
140 */
141int main(int argc, char *argv[])
142{
143 enum { NSAMPLES = 160, COUNT=100 };
144 pj_caching_pool cp;
145 pj_pool_t *pool;
146 pjmedia_port *wav;
147 pj_status_t status;
148
149
150 /* Verify cmd line arguments. */
151 if (argc != 2) {
152 puts("Error: missing argument(s)");
153 puts("Usage: latency REV.WAV");
154 return 1;
155 }
156
157 pj_log_set_level(0);
158
159 status = pj_init();
160 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
161
162 pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
163
164 pool = pj_pool_create( &cp.factory, /* pool factory */
165 "wav", /* pool name. */
166 4000, /* init size */
167 4000, /* increment size */
168 NULL /* callback on error */
169 );
170
171 pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
172 &pjmedia_strerror);
173
174 /* Wav */
175 status = pjmedia_wav_player_port_create( pool, /* memory pool */
176 argv[1], /* file to play */
177 0, /* use default ptime*/
178 0, /* flags */
179 0, /* default buffer */
180 &wav /* returned port */
181 );
182 if (status != PJ_SUCCESS) {
183 app_perror(THIS_FILE, argv[1], status);
184 return 1;
185 }
186
187 status = calculate_latency(pool, wav);
188 if (status != PJ_SUCCESS)
189 return 1;
190
191 status = pjmedia_port_destroy( wav );
192 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
193
194 pj_pool_release( pool );
195 pj_caching_pool_destroy( &cp );
196 pj_shutdown();
197
198 /* Done. */
199 return 0;
200}
201