blob: 4421c5e0339cb8a21039dba81d68f04128007aee [file] [log] [blame]
/* $Id$ */
/*
* Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
* Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include <stdio.h>
#include <ctype.h>
#include <pj/pool.h>
#include "test.h"
#define JB_INIT_PREFETCH 0
#define JB_MIN_PREFETCH 0
#define JB_MAX_PREFETCH 10
#define JB_PTIME 20
#define JB_BUF_SIZE 50
//#define REPORT
//#define PRINT_COMMENT
typedef struct test_param_t {
pj_bool_t adaptive;
unsigned init_prefetch;
unsigned min_prefetch;
unsigned max_prefetch;
} test_param_t;
typedef struct test_cond_t {
int burst;
int discard;
int lost;
int empty;
int delay; /**< Maximum delay, in frames. */
} test_cond_t;
static pj_bool_t parse_test_headers(char *line, test_param_t *param,
test_cond_t *cond)
{
char *p = line;
if (*p == '%') {
/* Test params. */
char mode_st[16];
sscanf(p+1, "%s %u %u %u", mode_st, &param->init_prefetch,
&param->min_prefetch, &param->max_prefetch);
param->adaptive = (pj_ansi_stricmp(mode_st, "adaptive") == 0);
} else if (*p == '!') {
/* Success condition. */
char cond_st[16];
unsigned cond_val;
sscanf(p+1, "%s %u", cond_st, &cond_val);
if (pj_ansi_stricmp(cond_st, "burst") == 0)
cond->burst = cond_val;
else if (pj_ansi_stricmp(cond_st, "delay") == 0)
cond->delay = cond_val;
else if (pj_ansi_stricmp(cond_st, "discard") == 0)
cond->discard = cond_val;
else if (pj_ansi_stricmp(cond_st, "empty") == 0)
cond->empty = cond_val;
else if (pj_ansi_stricmp(cond_st, "lost") == 0)
cond->lost = cond_val;
} else if (*p == '=') {
/* Test title. */
++p;
while (*p && isspace(*p)) ++p;
printf("%s", p);
} else {
/* Unknown header, perhaps this is the test data */
/* Skip spaces */
while (*p && isspace(*p)) ++p;
/* Test data started.*/
if (*p != 0)
return PJ_FALSE;
}
return PJ_TRUE;
}
static pj_bool_t process_test_data(char data, pjmedia_jbuf *jb,
pj_uint16_t *seq, pj_uint16_t *last_seq)
{
char frame[1];
char f_type;
pj_bool_t print_state = PJ_TRUE;
pj_bool_t data_eos = PJ_FALSE;
switch (toupper(data)) {
case 'G': /* Get */
pjmedia_jbuf_get_frame(jb, frame, &f_type);
break;
case 'P': /* Put */
pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq);
*last_seq = *seq;
++*seq;
break;
case 'L': /* Lost */
*last_seq = *seq;
++*seq;
printf("Lost\n");
break;
case 'R': /* Sequence restarts */
*seq = 1;
printf("Sequence restarting, from %u to %u\n", *last_seq, *seq);
break;
case 'J': /* Sequence jumps */
(*seq) += 5000;
printf("Sequence jumping, from %u to %u\n", *last_seq, *seq);
break;
case 'D': /* Frame duplicated */
pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq - 1);
break;
case 'O': /* Old/late frame */
pjmedia_jbuf_put_frame(jb, (void*)frame, 1, *seq - 10 - pj_rand()%40);
break;
case '.': /* End of test session. */
data_eos = PJ_TRUE;
break;
default:
print_state = PJ_FALSE;
printf("Unknown test data '%c'\n", data);
break;
}
if (data_eos)
return PJ_FALSE;
#ifdef REPORT
if (print_state) {
pjmedia_jb_state state;
pjmedia_jbuf_get_state(jb, &state);
printf("seq=%d\t%c\tsize=%d\tprefetch=%d\n",
*last_seq, toupper(data), state.size, state.prefetch);
}
#endif
return PJ_TRUE;
}
int jbuf_main(void)
{
FILE *input = fopen("JBTEST.DAT", "rt");
pj_bool_t data_eof = PJ_FALSE;
int old_log_level;
int rc = 0;
old_log_level = pj_log_get_level();
pj_log_set_level(5);
while (rc == 0 && !data_eof) {
pj_str_t jb_name = {"JBTEST", 6};
pjmedia_jbuf *jb;
pj_pool_t *pool;
pjmedia_jb_state state;
pj_uint16_t last_seq = 0;
pj_uint16_t seq = 1;
char line[1024], *p = NULL;
test_param_t param;
test_cond_t cond;
param.adaptive = PJ_TRUE;
param.init_prefetch = JB_INIT_PREFETCH;
param.min_prefetch = JB_MIN_PREFETCH;
param.max_prefetch = JB_MAX_PREFETCH;
cond.burst = -1;
cond.delay = -1;
cond.discard = -1;
cond.empty = -1;
cond.lost = -1;
printf("\n\n");
/* Parse test session title, param, and conditions */
do {
p = fgets(line, sizeof(line), input);
} while (p && parse_test_headers(line, &param, &cond));
/* EOF test data */
if (p == NULL)
break;
//printf("======================================================\n");
/* Initialize test session */
pool = pj_pool_create(mem, "JBPOOL", 256*16, 256*16, NULL);
pjmedia_jbuf_create(pool, &jb_name, 1, JB_PTIME, JB_BUF_SIZE, &jb);
pjmedia_jbuf_reset(jb);
if (param.adaptive) {
pjmedia_jbuf_set_adaptive(jb,
param.init_prefetch,
param.min_prefetch,
param.max_prefetch);
} else {
pjmedia_jbuf_set_fixed(jb, param.init_prefetch);
}
#ifdef REPORT
pjmedia_jbuf_get_state(jb, &state);
printf("Initial\tsize=%d\tprefetch=%d\tmin.pftch=%d\tmax.pftch=%d\n",
state.size, state.prefetch, state.min_prefetch,
state.max_prefetch);
#endif
/* Test session start */
while (1) {
int c;
/* Get next line of test data */
if (!p || *p == 0) {
p = fgets(line, sizeof(line), input);
if (p == NULL) {
data_eof = PJ_TRUE;
break;
}
}
/* Get next char of test data */
c = *p++;
/* Skip spaces */
if (isspace(c))
continue;
/* Print comment line */
if (c == '#') {
#ifdef PRINT_COMMENT
while (*p && isspace(*p)) ++p;
if (*p) printf("..%s", p);
#endif
*p = 0;
continue;
}
/* Process test data */
if (!process_test_data(c, jb, &seq, &last_seq))
break;
}
/* Print JB states */
pjmedia_jbuf_get_state(jb, &state);
printf("------------------------------------------------------\n");
printf("Summary:\n");
printf(" size=%d prefetch=%d\n", state.size, state.prefetch);
printf(" delay (min/max/avg/dev)=%d/%d/%d/%d ms\n",
state.min_delay, state.max_delay, state.avg_delay,
state.dev_delay);
printf(" lost=%d discard=%d empty=%d burst(avg)=%d\n",
state.lost, state.discard, state.empty, state.avg_burst);
/* Evaluate test session */
if (cond.burst >= 0 && (int)state.avg_burst > cond.burst) {
printf("! 'Burst' should be %d, it is %d\n",
cond.burst, state.avg_burst);
rc |= 1;
}
if (cond.delay >= 0 && (int)state.avg_delay/JB_PTIME > cond.delay) {
printf("! 'Delay' should be %d, it is %d\n",
cond.delay, state.avg_delay/JB_PTIME);
rc |= 2;
}
if (cond.discard >= 0 && (int)state.discard > cond.discard) {
printf("! 'Discard' should be %d, it is %d\n",
cond.discard, state.discard);
rc |= 4;
}
if (cond.empty >= 0 && (int)state.empty > cond.empty) {
printf("! 'Empty' should be %d, it is %d\n",
cond.empty, state.empty);
rc |= 8;
}
if (cond.lost >= 0 && (int)state.lost > cond.lost) {
printf("! 'Lost' should be %d, it is %d\n",
cond.lost, state.lost);
rc |= 16;
}
pjmedia_jbuf_destroy(jb);
pj_pool_release(pool);
}
fclose(input);
pj_log_set_level(old_log_level);
return rc;
}