diff 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
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/spandsp-0.0.3/spandsp-0.0.3/tests/playout_tests.c	Fri Jun 25 16:00:21 2010 +0200
@@ -0,0 +1,364 @@
+/*
+ * 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.
+ *
+ * $Id: playout_tests.c,v 1.16 2006/11/24 12:34:55 steveu Exp $
+ */
+
+/*! \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.
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdio.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <string.h>
+#if defined(HAVE_TGMATH_H)
+#include <tgmath.h>
+#endif
+#if defined(HAVE_MATH_H)
+#include <math.h>
+#endif
+#include <tiffio.h>
+
+#include <audiofile.h>
+
+#include "spandsp.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_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;
+    AFfilehandle inhandle;
+    AFfilehandle outhandle;
+    AFfilesetup filesetup;
+
+    filesetup = afNewFileSetup();
+    if (filesetup == AF_NULL_FILESETUP)
+    {
+        fprintf(stderr, "    Failed to create file setup\n");
+        exit(2);
+    }
+    afInitSampleFormat(filesetup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, 16);
+    afInitRate(filesetup, AF_DEFAULT_TRACK, (float) SAMPLE_RATE);
+    afInitFileFormat(filesetup, AF_FILE_WAVE);
+    afInitChannels(filesetup, AF_DEFAULT_TRACK, 2);
+
+    inhandle = afOpenFile(INPUT_FILE_NAME, "r", NULL);
+    if (inhandle == AF_NULL_FILEHANDLE)
+    {
+        fprintf(stderr, "    Failed to open wave file '%s'\n", INPUT_FILE_NAME);
+        exit(2);
+    }
+    outhandle = afOpenFile(OUTPUT_FILE_NAME, "w", filesetup);
+    if (outhandle == AF_NULL_FILEHANDLE)
+    {
+        fprintf(stderr, "    Failed to create wave 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_new(2*BLOCK_LEN, 15*BLOCK_LEN)) == NULL)
+        return;
+    plc_init(&plc);
+    time_scale_init(&ts, 1.0);
+    for (i = 0;  i < 1000000;  i++)
+    {
+        if (i >= next_actual_receive)
+        {
+            amp = malloc(BLOCK_LEN*sizeof(int16_t));
+            inframes = afReadFrames(inhandle,
+                                    AF_DEFAULT_TRACK,
+                                    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 = afWriteFrames(outhandle, AF_DEFAULT_TRACK, 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 = afWriteFrames(outhandle, AF_DEFAULT_TRACK, 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 (afCloseFile(inhandle) != 0)
+    {
+        fprintf(stderr, "    Cannot close wave file '%s'\n", INPUT_FILE_NAME);
+        exit(2);
+    }
+    if (afCloseFile(outhandle) != 0)
+    {
+        fprintf(stderr, "    Cannot close wave file '%s'\n", OUTPUT_FILE_NAME);
+        exit(2);
+    }
+    afFreeFileSetup(filesetup);
+
+    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_new(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 ------------------------------------------------------------*/

Repositories maintained by Peter Meerwald, pmeerw@pmeerw.net.