Mercurial > hg > audiostuff
comparison spandsp-0.0.6pre17/tests/playout_tests.c @ 4:26cd8f1ef0b1
import spandsp-0.0.6pre17
| author | Peter Meerwald <pmeerw@cosy.sbg.ac.at> | 
|---|---|
| date | Fri, 25 Jun 2010 15:50:58 +0200 | 
| parents | |
| children | 
   comparison
  equal
  deleted
  inserted
  replaced
| 3:c6c5a16ce2f2 | 4:26cd8f1ef0b1 | 
|---|---|
| 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.29 2009/05/30 15:23:14 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 #if defined(HAVE_CONFIG_H) | |
| 35 #include "config.h" | |
| 36 #endif | |
| 37 | |
| 38 #include <stdlib.h> | |
| 39 #include <stdio.h> | |
| 40 #include <string.h> | |
| 41 #include <sndfile.h> | |
| 42 | |
| 43 #include "spandsp.h" | |
| 44 #include "spandsp/private/time_scale.h" | |
| 45 #include "spandsp-sim.h" | |
| 46 | |
| 47 #define INPUT_FILE_NAME "playout_in.wav" | |
| 48 #define OUTPUT_FILE_NAME "playout_out.wav" | |
| 49 | |
| 50 #define BLOCK_LEN 160 | |
| 51 | |
| 52 static void dynamic_buffer_tests(void) | |
| 53 { | |
| 54 playout_state_t *s; | |
| 55 playout_frame_t frame; | |
| 56 playout_frame_t *p; | |
| 57 plc_state_t plc; | |
| 58 time_scale_state_t ts; | |
| 59 int16_t *amp; | |
| 60 int16_t fill[BLOCK_LEN]; | |
| 61 int16_t buf[20*BLOCK_LEN]; | |
| 62 int16_t out[10*BLOCK_LEN]; | |
| 63 timestamp_t time_stamp; | |
| 64 timestamp_t next_actual_receive; | |
| 65 timestamp_t next_scheduled_receive; | |
| 66 int near_far_time_offset; | |
| 67 int rng; | |
| 68 int i; | |
| 69 int j; | |
| 70 int ret; | |
| 71 int len; | |
| 72 int inframes; | |
| 73 int outframes; | |
| 74 SNDFILE *inhandle; | |
| 75 SNDFILE *outhandle; | |
| 76 | |
| 77 if ((inhandle = sf_open_telephony_read(INPUT_FILE_NAME, 1)) == NULL) | |
| 78 { | |
| 79 fprintf(stderr, " Failed to open audio file '%s'\n", INPUT_FILE_NAME); | |
| 80 exit(2); | |
| 81 } | |
| 82 if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL) | |
| 83 { | |
| 84 fprintf(stderr, " Failed to create audio file '%s'\n", OUTPUT_FILE_NAME); | |
| 85 exit(2); | |
| 86 } | |
| 87 | |
| 88 near_far_time_offset = 54321; | |
| 89 time_stamp = 12345; | |
| 90 next_actual_receive = time_stamp + near_far_time_offset; | |
| 91 next_scheduled_receive = 0; | |
| 92 for (i = 0; i < BLOCK_LEN; i++) | |
| 93 fill[i] = 32767; | |
| 94 | |
| 95 if ((s = playout_init(2*BLOCK_LEN, 15*BLOCK_LEN)) == NULL) | |
| 96 return; | |
| 97 plc_init(&plc); | |
| 98 time_scale_init(&ts, SAMPLE_RATE, 1.0); | |
| 99 for (i = 0; i < 1000000; i++) | |
| 100 { | |
| 101 if (i >= next_actual_receive) | |
| 102 { | |
| 103 amp = malloc(BLOCK_LEN*sizeof(int16_t)); | |
| 104 inframes = sf_readf_short(inhandle, amp, BLOCK_LEN); | |
| 105 if (inframes < BLOCK_LEN) | |
| 106 break; | |
| 107 ret = playout_put(s, | |
| 108 amp, | |
| 109 PLAYOUT_TYPE_SPEECH, | |
| 110 inframes, | |
| 111 time_stamp, | |
| 112 next_actual_receive); | |
| 113 #if 0 | |
| 114 switch (ret) | |
| 115 { | |
| 116 case PLAYOUT_OK: | |
| 117 printf("<< Record\n"); | |
| 118 break; | |
| 119 case PLAYOUT_ERROR: | |
| 120 printf("<< Error\n"); | |
| 121 break; | |
| 122 default: | |
| 123 printf("<< Eh?\n"); | |
| 124 break; | |
| 125 } | |
| 126 #endif | |
| 127 rng = rand() & 0xFF; | |
| 128 if (i < 100000) | |
| 129 rng = (rng*rng) >> 7; | |
| 130 else if (i < 200000) | |
| 131 rng = (rng*rng) >> 6; | |
| 132 else if (i < 300000) | |
| 133 rng = (rng*rng) >> 5; | |
| 134 else if (i < 400000) | |
| 135 rng = (rng*rng) >> 7; | |
| 136 time_stamp += BLOCK_LEN; | |
| 137 next_actual_receive = time_stamp + near_far_time_offset + rng; | |
| 138 } | |
| 139 if (i >= next_scheduled_receive) | |
| 140 { | |
| 141 do | |
| 142 { | |
| 143 ret = playout_get(s, &frame, next_scheduled_receive); | |
| 144 if (ret == PLAYOUT_DROP) | |
| 145 printf(">> Drop %d\n", next_scheduled_receive); | |
| 146 } | |
| 147 while (ret == PLAYOUT_DROP); | |
| 148 switch (ret) | |
| 149 { | |
| 150 case PLAYOUT_OK: | |
| 151 printf(">> Play %d\n", next_scheduled_receive); | |
| 152 plc_rx(&plc, frame.data, frame.sender_len); | |
| 153 len = time_scale(&ts, out, ((int16_t *) frame.data), frame.sender_len); | |
| 154 printf("len = %d\n", len); | |
| 155 for (j = 0; j < len; j++) | |
| 156 { | |
| 157 buf[2*j] = out[j]; | |
| 158 buf[2*j + 1] = 10*playout_current_length(s); | |
| 159 } | |
| 160 outframes = sf_writef_short(outhandle, buf, len); | |
| 161 if (outframes != len) | |
| 162 { | |
| 163 fprintf(stderr, " Error writing out sound\n"); | |
| 164 exit(2); | |
| 165 } | |
| 166 free(frame.data); | |
| 167 next_scheduled_receive += BLOCK_LEN; | |
| 168 break; | |
| 169 case PLAYOUT_FILLIN: | |
| 170 printf(">> Fill %d\n", next_scheduled_receive); | |
| 171 plc_fillin(&plc, fill, BLOCK_LEN); | |
| 172 time_scale_rate(&ts, 0.5); | |
| 173 len = time_scale(&ts, out, fill, BLOCK_LEN); | |
| 174 time_scale_rate(&ts, 1.0); | |
| 175 printf("len = %d\n", len); | |
| 176 for (j = 0; j < len; j++) | |
| 177 { | |
| 178 buf[2*j] = out[j]; | |
| 179 buf[2*j + 1] = 10*playout_current_length(s); | |
| 180 } | |
| 181 outframes = sf_writef_short(outhandle, buf, len); | |
| 182 if (outframes != len) | |
| 183 { | |
| 184 fprintf(stderr, " Error writing out sound\n"); | |
| 185 exit(2); | |
| 186 } | |
| 187 next_scheduled_receive += BLOCK_LEN; | |
| 188 break; | |
| 189 case PLAYOUT_DROP: | |
| 190 printf(">> Drop %d\n", next_scheduled_receive); | |
| 191 break; | |
| 192 case PLAYOUT_NOFRAME: | |
| 193 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); | |
| 194 next_scheduled_receive += BLOCK_LEN; | |
| 195 break; | |
| 196 case PLAYOUT_EMPTY: | |
| 197 printf(">> Empty %d\n", next_scheduled_receive); | |
| 198 next_scheduled_receive += BLOCK_LEN; | |
| 199 break; | |
| 200 case PLAYOUT_ERROR: | |
| 201 printf(">> Error %d\n", next_scheduled_receive); | |
| 202 next_scheduled_receive += BLOCK_LEN; | |
| 203 break; | |
| 204 default: | |
| 205 printf(">> Eh? %d\n", next_scheduled_receive); | |
| 206 break; | |
| 207 } | |
| 208 } | |
| 209 } | |
| 210 if (sf_close(inhandle) != 0) | |
| 211 { | |
| 212 fprintf(stderr, " Cannot close audio file '%s'\n", INPUT_FILE_NAME); | |
| 213 exit(2); | |
| 214 } | |
| 215 if (sf_close(outhandle) != 0) | |
| 216 { | |
| 217 fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME); | |
| 218 exit(2); | |
| 219 } | |
| 220 | |
| 221 printf("%10" PRId32 " %10" PRId32 " %10d\n", s->state_just_in_time, s->state_late, playout_current_length(s)); | |
| 222 | |
| 223 /* Clear everything from the queue */ | |
| 224 while ((p = playout_get_unconditional(s))) | |
| 225 /*free(p->data)*/; | |
| 226 /* Now free the context itself */ | |
| 227 playout_free(s); | |
| 228 } | |
| 229 /*- End of function --------------------------------------------------------*/ | |
| 230 | |
| 231 static void static_buffer_tests(void) | |
| 232 { | |
| 233 playout_state_t *s; | |
| 234 playout_frame_t frame; | |
| 235 playout_frame_t *p; | |
| 236 int type; | |
| 237 uint8_t fr[BLOCK_LEN]; | |
| 238 timestamp_t next_scheduled_send; | |
| 239 int transit_time; | |
| 240 timestamp_t next_actual_receive; | |
| 241 timestamp_t next_scheduled_receive; | |
| 242 int len; | |
| 243 int i; | |
| 244 int ret; | |
| 245 | |
| 246 next_scheduled_send = 0; | |
| 247 transit_time = 320; | |
| 248 next_actual_receive = next_scheduled_send + transit_time; | |
| 249 next_scheduled_receive = 960; | |
| 250 | |
| 251 memset(fr, 0, sizeof(fr)); | |
| 252 type = PLAYOUT_TYPE_SPEECH; | |
| 253 len = BLOCK_LEN; | |
| 254 | |
| 255 if ((s = playout_init(2*BLOCK_LEN, 2*BLOCK_LEN)) == NULL) | |
| 256 return; | |
| 257 for (i = 0; i < 1000000; i++) | |
| 258 { | |
| 259 if (i >= next_actual_receive) | |
| 260 { | |
| 261 ret = playout_put(s, | |
| 262 fr, | |
| 263 type, | |
| 264 len, | |
| 265 next_scheduled_send, | |
| 266 next_actual_receive); | |
| 267 switch (ret) | |
| 268 { | |
| 269 case PLAYOUT_OK: | |
| 270 printf("<< Record\n"); | |
| 271 break; | |
| 272 case PLAYOUT_ERROR: | |
| 273 printf("<< Error\n"); | |
| 274 break; | |
| 275 default: | |
| 276 printf("<< Eh?\n"); | |
| 277 break; | |
| 278 } | |
| 279 next_scheduled_send += BLOCK_LEN; | |
| 280 ret = rand() & 0xFF; | |
| 281 ret = (ret*ret) >> 7; | |
| 282 transit_time = 320 + ret; | |
| 283 next_actual_receive = next_scheduled_send + transit_time; | |
| 284 } | |
| 285 if (i >= next_scheduled_receive) | |
| 286 { | |
| 287 do | |
| 288 { | |
| 289 ret = playout_get(s, &frame, next_scheduled_receive); | |
| 290 } | |
| 291 while (ret == PLAYOUT_DROP); | |
| 292 switch (ret) | |
| 293 { | |
| 294 case PLAYOUT_OK: | |
| 295 printf(">> Play\n"); | |
| 296 next_scheduled_receive += BLOCK_LEN; | |
| 297 break; | |
| 298 case PLAYOUT_FILLIN: | |
| 299 printf(">> Fill\n"); | |
| 300 next_scheduled_receive += BLOCK_LEN; | |
| 301 break; | |
| 302 case PLAYOUT_DROP: | |
| 303 printf(">> Drop\n"); | |
| 304 break; | |
| 305 case PLAYOUT_NOFRAME: | |
| 306 printf(">> No frame\n"); | |
| 307 next_scheduled_receive += BLOCK_LEN; | |
| 308 break; | |
| 309 case PLAYOUT_EMPTY: | |
| 310 printf(">> Empty\n"); | |
| 311 next_scheduled_receive += BLOCK_LEN; | |
| 312 break; | |
| 313 case PLAYOUT_ERROR: | |
| 314 printf(">> Error\n"); | |
| 315 next_scheduled_receive += BLOCK_LEN; | |
| 316 break; | |
| 317 default: | |
| 318 printf(">> Eh?\n"); | |
| 319 break; | |
| 320 } | |
| 321 } | |
| 322 } | |
| 323 /* Clear everything from the queue */ | |
| 324 while ((p = playout_get_unconditional(s))) | |
| 325 /*free(p->data)*/; | |
| 326 /* Now free the context itself */ | |
| 327 playout_free(s); | |
| 328 } | |
| 329 /*- End of function --------------------------------------------------------*/ | |
| 330 | |
| 331 int main(int argc, char *argv[]) | |
| 332 { | |
| 333 printf("Dynamic buffering tests\n"); | |
| 334 dynamic_buffer_tests(); | |
| 335 printf("Static buffering tests\n"); | |
| 336 static_buffer_tests(); | |
| 337 } | |
| 338 /*- End of function --------------------------------------------------------*/ | |
| 339 /*- End of file ------------------------------------------------------------*/ | 
