Mercurial > hg > audiostuff
comparison spandsp-0.0.3/spandsp-0.0.3/tests/playout_tests.c @ 5:f762bf195c4b
import spandsp-0.0.3
author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> |
---|---|
date | Fri, 25 Jun 2010 16:00:21 +0200 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
4:26cd8f1ef0b1 | 5:f762bf195c4b |
---|---|
1 /* | |
2 * SpanDSP - a series of DSP components for telephony | |
3 * | |
4 * playout_tests.c | |
5 * | |
6 * Written by Steve Underwood <steveu@coppice.org> | |
7 * | |
8 * Copyright (C) 2005 Steve Underwood | |
9 * | |
10 * All rights reserved. | |
11 * | |
12 * This program is free software; you can redistribute it and/or modify | |
13 * it under the terms of the GNU General Public License version 2, as | |
14 * published by the Free Software Foundation. | |
15 * | |
16 * This program is distributed in the hope that it will be useful, | |
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
19 * GNU General Public License for more details. | |
20 * | |
21 * You should have received a copy of the GNU General Public License | |
22 * along with this program; if not, write to the Free Software | |
23 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
24 * | |
25 * $Id: playout_tests.c,v 1.16 2006/11/24 12:34:55 steveu Exp $ | |
26 */ | |
27 | |
28 /*! \page playout_tests_page Playout (jitter buffering) tests | |
29 \section playout_tests_page_sec_1 What does it do? | |
30 These tests simulate timing jitter and packet loss in an audio stream, and see | |
31 how well the playout module copes. | |
32 */ | |
33 | |
34 #ifdef HAVE_CONFIG_H | |
35 #include "config.h" | |
36 #endif | |
37 | |
38 #include <stdio.h> | |
39 #include <inttypes.h> | |
40 #include <stdlib.h> | |
41 #include <string.h> | |
42 #if defined(HAVE_TGMATH_H) | |
43 #include <tgmath.h> | |
44 #endif | |
45 #if defined(HAVE_MATH_H) | |
46 #include <math.h> | |
47 #endif | |
48 #include <tiffio.h> | |
49 | |
50 #include <audiofile.h> | |
51 | |
52 #include "spandsp.h" | |
53 | |
54 #define INPUT_FILE_NAME "playout_in.wav" | |
55 #define OUTPUT_FILE_NAME "playout_out.wav" | |
56 | |
57 #define BLOCK_LEN 160 | |
58 | |
59 static void dynamic_buffer_tests(void) | |
60 { | |
61 playout_state_t *s; | |
62 playout_frame_t frame; | |
63 playout_frame_t *p; | |
64 plc_state_t plc; | |
65 time_scale_t ts; | |
66 int16_t *amp; | |
67 int16_t fill[BLOCK_LEN]; | |
68 int16_t buf[20*BLOCK_LEN]; | |
69 int16_t out[10*BLOCK_LEN]; | |
70 timestamp_t time_stamp; | |
71 timestamp_t next_actual_receive; | |
72 timestamp_t next_scheduled_receive; | |
73 int near_far_time_offset; | |
74 int rng; | |
75 int i; | |
76 int j; | |
77 int ret; | |
78 int len; | |
79 int inframes; | |
80 int outframes; | |
81 AFfilehandle inhandle; | |
82 AFfilehandle outhandle; | |
83 AFfilesetup filesetup; | |
84 | |
85 filesetup = afNewFileSetup(); | |
86 if (filesetup == AF_NULL_FILESETUP) | |
87 { | |
88 fprintf(stderr, " Failed to create file setup\n"); | |
89 exit(2); | |
90 } | |
91 afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16); | |
92 afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE); | |
93 afInitFileFormat(filesetup, AF_FILE_WAVE); | |
94 afInitChannels(filesetup, AF_DEFAULT_TRACK, 2); | |
95 | |
96 inhandle = afOpenFile(INPUT_FILE_NAME, "r", NULL); | |
97 if (inhandle == AF_NULL_FILEHANDLE) | |
98 { | |
99 fprintf(stderr, " Failed to open wave file '%s'\n", INPUT_FILE_NAME); | |
100 exit(2); | |
101 } | |
102 outhandle = afOpenFile(OUTPUT_FILE_NAME, "w", filesetup); | |
103 if (outhandle == AF_NULL_FILEHANDLE) | |
104 { | |
105 fprintf(stderr, " Failed to create wave file '%s'\n", OUTPUT_FILE_NAME); | |
106 exit(2); | |
107 } | |
108 | |
109 near_far_time_offset = 54321; | |
110 time_stamp = 12345; | |
111 next_actual_receive = time_stamp + near_far_time_offset; | |
112 next_scheduled_receive = 0; | |
113 for (i = 0; i < BLOCK_LEN; i++) | |
114 fill[i] = 32767; | |
115 | |
116 if ((s = playout_new(2*BLOCK_LEN, 15*BLOCK_LEN)) == NULL) | |
117 return; | |
118 plc_init(&plc); | |
119 time_scale_init(&ts, 1.0); | |
120 for (i = 0; i < 1000000; i++) | |
121 { | |
122 if (i >= next_actual_receive) | |
123 { | |
124 amp = malloc(BLOCK_LEN*sizeof(int16_t)); | |
125 inframes = afReadFrames(inhandle, | |
126 AF_DEFAULT_TRACK, | |
127 amp, | |
128 BLOCK_LEN); | |
129 if (inframes < BLOCK_LEN) | |
130 break; | |
131 ret = playout_put(s, | |
132 amp, | |
133 PLAYOUT_TYPE_SPEECH, | |
134 inframes, | |
135 time_stamp, | |
136 next_actual_receive); | |
137 #if 0 | |
138 switch (ret) | |
139 { | |
140 case PLAYOUT_OK: | |
141 printf("<< Record\n"); | |
142 break; | |
143 case PLAYOUT_ERROR: | |
144 printf("<< Error\n"); | |
145 break; | |
146 default: | |
147 printf("<< Eh?\n"); | |
148 break; | |
149 } | |
150 #endif | |
151 rng = rand() & 0xFF; | |
152 if (i < 100000) | |
153 rng = (rng*rng) >> 7; | |
154 else if (i < 200000) | |
155 rng = (rng*rng) >> 6; | |
156 else if (i < 300000) | |
157 rng = (rng*rng) >> 5; | |
158 else if (i < 400000) | |
159 rng = (rng*rng) >> 7; | |
160 time_stamp += BLOCK_LEN; | |
161 next_actual_receive = time_stamp + near_far_time_offset + rng; | |
162 } | |
163 if (i >= next_scheduled_receive) | |
164 { | |
165 do | |
166 { | |
167 ret = playout_get(s, &frame, next_scheduled_receive); | |
168 if (ret == PLAYOUT_DROP) | |
169 printf(">> Drop %d\n", next_scheduled_receive); | |
170 } | |
171 while (ret == PLAYOUT_DROP); | |
172 switch (ret) | |
173 { | |
174 case PLAYOUT_OK: | |
175 printf(">> Play %d\n", next_scheduled_receive); | |
176 plc_rx(&plc, frame.data, frame.sender_len); | |
177 len = time_scale(&ts, out, ((int16_t *) frame.data), frame.sender_len); | |
178 printf("len = %d\n", len); | |
179 for (j = 0; j < len; j++) | |
180 { | |
181 buf[2*j] = out[j]; | |
182 buf[2*j + 1] = 10*playout_current_length(s); | |
183 } | |
184 outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, buf, len); | |
185 if (outframes != len) | |
186 { | |
187 fprintf(stderr, " Error writing out sound\n"); | |
188 exit(2); | |
189 } | |
190 free(frame.data); | |
191 next_scheduled_receive += BLOCK_LEN; | |
192 break; | |
193 case PLAYOUT_FILLIN: | |
194 printf(">> Fill %d\n", next_scheduled_receive); | |
195 plc_fillin(&plc, fill, BLOCK_LEN); | |
196 time_scale_rate(&ts, 0.5); | |
197 len = time_scale(&ts, out, fill, BLOCK_LEN); | |
198 time_scale_rate(&ts, 1.0); | |
199 printf("len = %d\n", len); | |
200 for (j = 0; j < len; j++) | |
201 { | |
202 buf[2*j] = out[j]; | |
203 buf[2*j + 1] = 10*playout_current_length(s); | |
204 } | |
205 outframes = afWriteFrames(outhandle, AF_DEFAULT_TRACK, buf, len); | |
206 if (outframes != len) | |
207 { | |
208 fprintf(stderr, " Error writing out sound\n"); | |
209 exit(2); | |
210 } | |
211 next_scheduled_receive += BLOCK_LEN; | |
212 break; | |
213 case PLAYOUT_DROP: | |
214 printf(">> Drop %d\n", next_scheduled_receive); | |
215 break; | |
216 case PLAYOUT_NOFRAME: | |
217 printf(">> No frame %d %d %d %d\n", next_scheduled_receive, playout_next_due(s), s->last_speech_sender_stamp, s->last_speech_sender_len); | |
218 next_scheduled_receive += BLOCK_LEN; | |
219 break; | |
220 case PLAYOUT_EMPTY: | |
221 printf(">> Empty %d\n", next_scheduled_receive); | |
222 next_scheduled_receive += BLOCK_LEN; | |
223 break; | |
224 case PLAYOUT_ERROR: | |
225 printf(">> Error %d\n", next_scheduled_receive); | |
226 next_scheduled_receive += BLOCK_LEN; | |
227 break; | |
228 default: | |
229 printf(">> Eh? %d\n", next_scheduled_receive); | |
230 break; | |
231 } | |
232 } | |
233 } | |
234 if (afCloseFile(inhandle) != 0) | |
235 { | |
236 fprintf(stderr, " Cannot close wave file '%s'\n", INPUT_FILE_NAME); | |
237 exit(2); | |
238 } | |
239 if (afCloseFile(outhandle) != 0) | |
240 { | |
241 fprintf(stderr, " Cannot close wave file '%s'\n", OUTPUT_FILE_NAME); | |
242 exit(2); | |
243 } | |
244 afFreeFileSetup(filesetup); | |
245 | |
246 printf("%10" PRId32 " %10" PRId32 " %10d\n", s->state_just_in_time, s->state_late, playout_current_length(s)); | |
247 | |
248 /* Clear everything from the queue */ | |
249 while ((p = playout_get_unconditional(s))) | |
250 /*free(p->data)*/; | |
251 /* Now free the context itself */ | |
252 playout_free(s); | |
253 } | |
254 /*- End of function --------------------------------------------------------*/ | |
255 | |
256 static void static_buffer_tests(void) | |
257 { | |
258 playout_state_t *s; | |
259 playout_frame_t frame; | |
260 playout_frame_t *p; | |
261 int type; | |
262 uint8_t fr[BLOCK_LEN]; | |
263 timestamp_t next_scheduled_send; | |
264 int transit_time; | |
265 timestamp_t next_actual_receive; | |
266 timestamp_t next_scheduled_receive; | |
267 int len; | |
268 int i; | |
269 int ret; | |
270 | |
271 next_scheduled_send = 0; | |
272 transit_time = 320; | |
273 next_actual_receive = next_scheduled_send + transit_time; | |
274 next_scheduled_receive = 960; | |
275 | |
276 memset(fr, 0, sizeof(fr)); | |
277 type = PLAYOUT_TYPE_SPEECH; | |
278 len = BLOCK_LEN; | |
279 | |
280 if ((s = playout_new(2*BLOCK_LEN, 2*BLOCK_LEN)) == NULL) | |
281 return; | |
282 for (i = 0; i < 1000000; i++) | |
283 { | |
284 if (i >= next_actual_receive) | |
285 { | |
286 ret = playout_put(s, | |
287 fr, | |
288 type, | |
289 len, | |
290 next_scheduled_send, | |
291 next_actual_receive); | |
292 switch (ret) | |
293 { | |
294 case PLAYOUT_OK: | |
295 printf("<< Record\n"); | |
296 break; | |
297 case PLAYOUT_ERROR: | |
298 printf("<< Error\n"); | |
299 break; | |
300 default: | |
301 printf("<< Eh?\n"); | |
302 break; | |
303 } | |
304 next_scheduled_send += BLOCK_LEN; | |
305 ret = rand() & 0xFF; | |
306 ret = (ret*ret) >> 7; | |
307 transit_time = 320 + ret; | |
308 next_actual_receive = next_scheduled_send + transit_time; | |
309 } | |
310 if (i >= next_scheduled_receive) | |
311 { | |
312 do | |
313 { | |
314 ret = playout_get(s, &frame, next_scheduled_receive); | |
315 } | |
316 while (ret == PLAYOUT_DROP); | |
317 switch (ret) | |
318 { | |
319 case PLAYOUT_OK: | |
320 printf(">> Play\n"); | |
321 next_scheduled_receive += BLOCK_LEN; | |
322 break; | |
323 case PLAYOUT_FILLIN: | |
324 printf(">> Fill\n"); | |
325 next_scheduled_receive += BLOCK_LEN; | |
326 break; | |
327 case PLAYOUT_DROP: | |
328 printf(">> Drop\n"); | |
329 break; | |
330 case PLAYOUT_NOFRAME: | |
331 printf(">> No frame\n"); | |
332 next_scheduled_receive += BLOCK_LEN; | |
333 break; | |
334 case PLAYOUT_EMPTY: | |
335 printf(">> Empty\n"); | |
336 next_scheduled_receive += BLOCK_LEN; | |
337 break; | |
338 case PLAYOUT_ERROR: | |
339 printf(">> Error\n"); | |
340 next_scheduled_receive += BLOCK_LEN; | |
341 break; | |
342 default: | |
343 printf(">> Eh?\n"); | |
344 break; | |
345 } | |
346 } | |
347 } | |
348 /* Clear everything from the queue */ | |
349 while ((p = playout_get_unconditional(s))) | |
350 /*free(p->data)*/; | |
351 /* Now free the context itself */ | |
352 playout_free(s); | |
353 } | |
354 /*- End of function --------------------------------------------------------*/ | |
355 | |
356 int main(int argc, char *argv[]) | |
357 { | |
358 printf("Dynamic buffering tests\n"); | |
359 dynamic_buffer_tests(); | |
360 printf("Static buffering tests\n"); | |
361 static_buffer_tests(); | |
362 } | |
363 /*- End of function --------------------------------------------------------*/ | |
364 /*- End of file ------------------------------------------------------------*/ |