123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337 |
- /*
- * SpanDSP - a series of DSP components for telephony
- *
- * playout_tests.c
- *
- * Written by Steve Underwood <steveu@coppice.org>
- *
- * Copyright (C) 2005 Steve Underwood
- *
- * All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2, as
- * published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
- /*! \page playout_tests_page Playout (jitter buffering) tests
- \section playout_tests_page_sec_1 What does it do?
- These tests simulate timing jitter and packet loss in an audio stream, and see
- how well the playout module copes.
- */
- #if defined(HAVE_CONFIG_H)
- #include "config.h"
- #endif
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <sndfile.h>
- #include "spandsp.h"
- #include "spandsp/private/time_scale.h"
- #include "spandsp-sim.h"
- #define INPUT_FILE_NAME "playout_in.wav"
- #define OUTPUT_FILE_NAME "playout_out.wav"
- #define BLOCK_LEN 160
- static void dynamic_buffer_tests(void)
- {
- playout_state_t *s;
- playout_frame_t frame;
- playout_frame_t *p;
- plc_state_t plc;
- time_scale_state_t ts;
- int16_t *amp;
- int16_t fill[BLOCK_LEN];
- int16_t buf[20*BLOCK_LEN];
- int16_t out[10*BLOCK_LEN];
- timestamp_t time_stamp;
- timestamp_t next_actual_receive;
- timestamp_t next_scheduled_receive;
- int near_far_time_offset;
- int rng;
- int i;
- int j;
- int ret;
- int len;
- int inframes;
- int outframes;
- SNDFILE *inhandle;
- SNDFILE *outhandle;
- if ((inhandle = sf_open_telephony_read(INPUT_FILE_NAME, 1)) == NULL)
- {
- fprintf(stderr, " Failed to open audio file '%s'\n", INPUT_FILE_NAME);
- exit(2);
- }
- if ((outhandle = sf_open_telephony_write(OUTPUT_FILE_NAME, 1)) == NULL)
- {
- fprintf(stderr, " Failed to create audio file '%s'\n", OUTPUT_FILE_NAME);
- exit(2);
- }
- near_far_time_offset = 54321;
- time_stamp = 12345;
- next_actual_receive = time_stamp + near_far_time_offset;
- next_scheduled_receive = 0;
- for (i = 0; i < BLOCK_LEN; i++)
- fill[i] = 32767;
- if ((s = playout_init(2*BLOCK_LEN, 15*BLOCK_LEN)) == NULL)
- return;
- plc_init(&plc);
- time_scale_init(&ts, SAMPLE_RATE, 1.0);
- for (i = 0; i < 1000000; i++)
- {
- if (i >= next_actual_receive)
- {
- amp = malloc(BLOCK_LEN*sizeof(int16_t));
- inframes = sf_readf_short(inhandle, amp, BLOCK_LEN);
- if (inframes < BLOCK_LEN)
- break;
- ret = playout_put(s,
- amp,
- PLAYOUT_TYPE_SPEECH,
- inframes,
- time_stamp,
- next_actual_receive);
- #if 0
- switch (ret)
- {
- case PLAYOUT_OK:
- printf("<< Record\n");
- break;
- case PLAYOUT_ERROR:
- printf("<< Error\n");
- break;
- default:
- printf("<< Eh?\n");
- break;
- }
- #endif
- rng = rand() & 0xFF;
- if (i < 100000)
- rng = (rng*rng) >> 7;
- else if (i < 200000)
- rng = (rng*rng) >> 6;
- else if (i < 300000)
- rng = (rng*rng) >> 5;
- else if (i < 400000)
- rng = (rng*rng) >> 7;
- time_stamp += BLOCK_LEN;
- next_actual_receive = time_stamp + near_far_time_offset + rng;
- }
- if (i >= next_scheduled_receive)
- {
- do
- {
- ret = playout_get(s, &frame, next_scheduled_receive);
- if (ret == PLAYOUT_DROP)
- printf(">> Drop %d\n", next_scheduled_receive);
- }
- while (ret == PLAYOUT_DROP);
- switch (ret)
- {
- case PLAYOUT_OK:
- printf(">> Play %d\n", next_scheduled_receive);
- plc_rx(&plc, frame.data, frame.sender_len);
- len = time_scale(&ts, out, ((int16_t *) frame.data), frame.sender_len);
- printf("len = %d\n", len);
- for (j = 0; j < len; j++)
- {
- buf[2*j] = out[j];
- buf[2*j + 1] = 10*playout_current_length(s);
- }
- outframes = sf_writef_short(outhandle, buf, len);
- if (outframes != len)
- {
- fprintf(stderr, " Error writing out sound\n");
- exit(2);
- }
- free(frame.data);
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_FILLIN:
- printf(">> Fill %d\n", next_scheduled_receive);
- plc_fillin(&plc, fill, BLOCK_LEN);
- time_scale_rate(&ts, 0.5);
- len = time_scale(&ts, out, fill, BLOCK_LEN);
- time_scale_rate(&ts, 1.0);
- printf("len = %d\n", len);
- for (j = 0; j < len; j++)
- {
- buf[2*j] = out[j];
- buf[2*j + 1] = 10*playout_current_length(s);
- }
- outframes = sf_writef_short(outhandle, buf, len);
- if (outframes != len)
- {
- fprintf(stderr, " Error writing out sound\n");
- exit(2);
- }
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_DROP:
- printf(">> Drop %d\n", next_scheduled_receive);
- break;
- case PLAYOUT_NOFRAME:
- 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);
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_EMPTY:
- printf(">> Empty %d\n", next_scheduled_receive);
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_ERROR:
- printf(">> Error %d\n", next_scheduled_receive);
- next_scheduled_receive += BLOCK_LEN;
- break;
- default:
- printf(">> Eh? %d\n", next_scheduled_receive);
- break;
- }
- }
- }
- if (sf_close_telephony(inhandle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", INPUT_FILE_NAME);
- exit(2);
- }
- if (sf_close_telephony(outhandle))
- {
- fprintf(stderr, " Cannot close audio file '%s'\n", OUTPUT_FILE_NAME);
- exit(2);
- }
- printf("%10" PRId32 " %10" PRId32 " %10d\n", s->state_just_in_time, s->state_late, playout_current_length(s));
- /* Clear everything from the queue */
- while ((p = playout_get_unconditional(s)))
- /*free(p->data)*/;
- /* Now free the context itself */
- playout_free(s);
- }
- /*- End of function --------------------------------------------------------*/
- static void static_buffer_tests(void)
- {
- playout_state_t *s;
- playout_frame_t frame;
- playout_frame_t *p;
- int type;
- uint8_t fr[BLOCK_LEN];
- timestamp_t next_scheduled_send;
- int transit_time;
- timestamp_t next_actual_receive;
- timestamp_t next_scheduled_receive;
- int len;
- int i;
- int ret;
- next_scheduled_send = 0;
- transit_time = 320;
- next_actual_receive = next_scheduled_send + transit_time;
- next_scheduled_receive = 960;
- memset(fr, 0, sizeof(fr));
- type = PLAYOUT_TYPE_SPEECH;
- len = BLOCK_LEN;
- if ((s = playout_init(2*BLOCK_LEN, 2*BLOCK_LEN)) == NULL)
- return;
- for (i = 0; i < 1000000; i++)
- {
- if (i >= next_actual_receive)
- {
- ret = playout_put(s,
- fr,
- type,
- len,
- next_scheduled_send,
- next_actual_receive);
- switch (ret)
- {
- case PLAYOUT_OK:
- printf("<< Record\n");
- break;
- case PLAYOUT_ERROR:
- printf("<< Error\n");
- break;
- default:
- printf("<< Eh?\n");
- break;
- }
- next_scheduled_send += BLOCK_LEN;
- ret = rand() & 0xFF;
- ret = (ret*ret) >> 7;
- transit_time = 320 + ret;
- next_actual_receive = next_scheduled_send + transit_time;
- }
- if (i >= next_scheduled_receive)
- {
- do
- {
- ret = playout_get(s, &frame, next_scheduled_receive);
- }
- while (ret == PLAYOUT_DROP);
- switch (ret)
- {
- case PLAYOUT_OK:
- printf(">> Play\n");
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_FILLIN:
- printf(">> Fill\n");
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_DROP:
- printf(">> Drop\n");
- break;
- case PLAYOUT_NOFRAME:
- printf(">> No frame\n");
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_EMPTY:
- printf(">> Empty\n");
- next_scheduled_receive += BLOCK_LEN;
- break;
- case PLAYOUT_ERROR:
- printf(">> Error\n");
- next_scheduled_receive += BLOCK_LEN;
- break;
- default:
- printf(">> Eh?\n");
- break;
- }
- }
- }
- /* Clear everything from the queue */
- while ((p = playout_get_unconditional(s)))
- /*free(p->data)*/;
- /* Now free the context itself */
- playout_free(s);
- }
- /*- End of function --------------------------------------------------------*/
- int main(int argc, char *argv[])
- {
- printf("Dynamic buffering tests\n");
- dynamic_buffer_tests();
- printf("Static buffering tests\n");
- static_buffer_tests();
- }
- /*- End of function --------------------------------------------------------*/
- /*- End of file ------------------------------------------------------------*/
|