⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sndtest.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
/* $Id: sndtest.c 974 2007-02-19 01:13:53Z bennylp $ */
/* 
 * Copyright (C) 2003-2007 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 
 */

/**
 * \page page_pjmedia_samples_sndtest_c Samples: Sound Card Benchmark
 *
 * This example can be used to benchmark the quality of the sound card
 * installed in the system. At the end of the test, it will report
 * the jitter and clock drifts of the device.
 *
 * This file is pjsip-apps/src/samples/sndtest.c
 *
 * Screenshots on WinXP: \image html sndtest.jpg
 *
 * \includelineno sndtest.c
 */


#include <pjmedia.h>
#include <pjlib.h>
#include <pjlib-util.h>

#include <stdlib.h>	/* atoi() */
#include <stdio.h>



#define THIS_FILE	    "sndtest.c"

/* Warn (print log with yellow color) if frame jitter is larger than
 * this value (in usec).
 */
#define WARN_JITTER_USEC    1000

/* Test duration in msec */
#define DURATION	    10000

/* Skip the first msec from the calculation */
#define SKIP_DURATION	    1000

/* Max frames per sec (to calculate number of delays to keep). */
#define MAX_FRAMES_PER_SEC  100

/* Number of frame durations to keep */
#define MAX_DELAY_COUNTER   (((DURATION/1000)+1)*MAX_FRAMES_PER_SEC)


struct stream_data
{
    pj_uint32_t	    first_timestamp;
    pj_uint32_t	    last_timestamp;
    pj_timestamp    last_called;
    unsigned	    counter;
    unsigned	    min_delay;
    unsigned	    max_delay;
    unsigned	    delay[MAX_DELAY_COUNTER];
};

struct test_data {
    pjmedia_dir dir;
    unsigned clock_rate;
    unsigned samples_per_frame;
    unsigned channel_count;
    pj_bool_t running;
    pj_bool_t has_error;

    struct stream_data capture_data;
    struct stream_data playback_data;
};



static const char *desc = 
 " sndtest.c						\n"
 "							\n"
 " PURPOSE:						\n"
 "  Test the performance of sound device.		\n"
 "							\n"
 " USAGE:						\n"
 "  sndtest --help					\n"
 "  sndtest [options]					\n"
 "							\n"
 " where options:					\n"
 "  --id=ID          -i  Use device ID (default is -1)	\n"
 "  --rate=HZ        -r  Set test clock rate (default=8000)\n"
 "  --frame=SAMPLES  -f  Set number of samples per frame\n"
 "  --channel=CH     -n  Set number of channels (default=1)\n"
 "  --verbose        -v  Show verbose result		\n"
 "  --help           -h  Show this screen		\n"
;



static void enum_devices(void)
{
    int i, count;
    
    count = pjmedia_snd_get_dev_count();
    if (count == 0) {
	PJ_LOG(3,(THIS_FILE, "No devices found"));
	return;
    }

    PJ_LOG(3,(THIS_FILE, "Found %d devices:", count));
    for (i=0; i<count; ++i) {
	const pjmedia_snd_dev_info *info;

	info = pjmedia_snd_get_dev_info(i);
	pj_assert(info != NULL);

	PJ_LOG(3,(THIS_FILE," %d: %s (capture=%d, playback=%d)",
	          i, info->name, info->input_count, info->output_count));
    }
}


static pj_status_t play_cb(void *user_data, pj_uint32_t timestamp,
			   void *output, unsigned size)
{
    struct test_data *test_data = user_data;
    struct stream_data *strm_data = &test_data->playback_data;

    /* Skip frames when test is not started or test has finished */
    if (!test_data->running) {
	pj_bzero(output, size);
	return PJ_SUCCESS;
    }

    /* Save last timestamp seen (to calculate drift) */
    strm_data->last_timestamp = timestamp;

    if (strm_data->last_called.u64 == 0) {
	pj_get_timestamp(&strm_data->last_called);
	/* Init min_delay to one frame */
	strm_data->min_delay = test_data->samples_per_frame * 1000000 /
			       test_data->clock_rate;
	strm_data->first_timestamp = timestamp;

    } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
	pj_timestamp now;
	unsigned delay;

	pj_get_timestamp(&now);
	
	/* Calculate frame interval */
	delay = pj_elapsed_usec(&strm_data->last_called, &now);
	if (delay < strm_data->min_delay)
	    strm_data->min_delay = delay;
	if (delay > strm_data->max_delay)
	    strm_data->max_delay = delay;

	strm_data->last_called = now;

	/* Save the frame interval for later calculation */
	strm_data->delay[strm_data->counter] = delay;
	++strm_data->counter;

    } else {

	/* No space, can't take anymore frames */
	test_data->running = 0;

    }

    pj_bzero(output, size);
    return PJ_SUCCESS;
}

static pj_status_t rec_cb(void *user_data, pj_uint32_t timestamp,
			  void *input, unsigned size)
{

    struct test_data *test_data = user_data;
    struct stream_data *strm_data = &test_data->capture_data;

    PJ_UNUSED_ARG(input);
    PJ_UNUSED_ARG(size);

    /* Skip frames when test is not started or test has finished */
    if (!test_data->running) {
	return PJ_SUCCESS;
    }

    /* Save last timestamp seen (to calculate drift) */
    strm_data->last_timestamp = timestamp;

    if (strm_data->last_called.u64 == 0) {
	pj_get_timestamp(&strm_data->last_called);
	/* Init min_delay to one frame */
	strm_data->min_delay = test_data->samples_per_frame * 1000000 /
			       test_data->clock_rate;
	strm_data->first_timestamp = timestamp;

    } else if (strm_data->counter <= MAX_DELAY_COUNTER) {
	pj_timestamp now;
	unsigned delay;

	pj_get_timestamp(&now);

	/* Calculate frame interval */
	delay = pj_elapsed_usec(&strm_data->last_called, &now);
	if (delay < strm_data->min_delay)
	    strm_data->min_delay = delay;
	if (delay > strm_data->max_delay)
	    strm_data->max_delay = delay;

	strm_data->last_called = now;

	/* Save the frame interval for later calculation */
	strm_data->delay[strm_data->counter] = delay;
	++strm_data->counter;

    } else {

	/* No space, can't take anymore frames */
	test_data->running = 0;

    }

    return PJ_SUCCESS;
}

static void app_perror(const char *title, pj_status_t status)
{
    char errmsg[PJ_ERR_MSG_SIZE];

    pj_strerror(status, errmsg, sizeof(errmsg));	
    printf( "%s: %s (err=%d)\n",
	    title, errmsg, status);
}


static void print_stream_data(const char *title, 
			      struct test_data *test_data,
			      struct stream_data *strm_data,
			      int verbose)
{
    unsigned i, dur;
    int ptime;
    unsigned min_jitter, max_jitter, sum_jitter, avg_jitter=0;

    PJ_LOG(3,(THIS_FILE, "  %s stream report:", title));

    /* Check that frames are captured/played */
    if (strm_data->counter == 0) {
	PJ_LOG(1,(THIS_FILE, "   Error: no frames are captured/played!"));
	test_data->has_error = 1;
	return;
    }

    /* Duration */
    dur = (strm_data->counter+1) * test_data->samples_per_frame * 1000 /
		test_data->clock_rate;
    PJ_LOG(3,(THIS_FILE, "   Duration: %ds.%03d",
	      dur/1000, dur%1000));

    /* Frame interval */
    if (strm_data->max_delay - strm_data->min_delay < WARN_JITTER_USEC) {
	PJ_LOG(3,(THIS_FILE, 
		  "   Frame interval: min=%d.%03dms, max=%d.%03dms",
		  strm_data->min_delay/1000, strm_data->min_delay%1000,
		  strm_data->max_delay/1000, strm_data->max_delay%1000));
    } else {
	test_data->has_error = 1;
	PJ_LOG(2,(THIS_FILE, 
		  "   Frame interval: min=%d.%03dms, max=%d.%03dms",
		  strm_data->min_delay/1000, strm_data->min_delay%1000,
		  strm_data->max_delay/1000, strm_data->max_delay%1000));
    }

    if (verbose) {
	unsigned i;
	unsigned decor = pj_log_get_decor();

	PJ_LOG(3,(THIS_FILE, "    Dumping frame delays:"));

	pj_log_set_decor(0);
	for (i=0; i<strm_data->counter; ++i)
	    PJ_LOG(3,(THIS_FILE, " %d.%03d", strm_data->delay[i]/1000, 
		      strm_data->delay[i]%1000));
	PJ_LOG(3,(THIS_FILE, "\r\n"));
	pj_log_set_decor(decor);
    }

    /* Calculate frame ptime in usec */

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -