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

📄 sndtest.c

📁 一个开源SIP协议栈
💻 C
📖 第 1 页 / 共 2 页
字号:
    ptime = test_data->samples_per_frame * 1000000 /
	    test_data->clock_rate;

    /* Calculate jitter */
    min_jitter = 0xFFFFF;
    max_jitter = 0;
    sum_jitter = 0;

    for (i=1; i<strm_data->counter; ++i) {
	int jitter1, jitter2, jitter;

	/* jitter1 is interarrival difference */
	jitter1 = strm_data->delay[i] - strm_data->delay[i-1];
	if (jitter1 < 0) jitter1 = -jitter1;
	
	/* jitter2 is difference between actual and scheduled arrival.
	 * This is intended to capture situation when frames are coming
	 * instantaneously, which will calculate as zero jitter with
	 * jitter1 calculation.
	 */
	jitter2 = ptime - strm_data->delay[i];
	if (jitter2 < 0) jitter2 = -jitter2;

	/* Set jitter as the maximum of the two jitter calculations. 
	 * This is intended to show the worst result.
	 */
	jitter = (jitter1>jitter2) ? jitter1 : jitter2;

	/* Calculate min, max, avg jitter */
	if (jitter < (int)min_jitter) min_jitter = jitter;
	if (jitter > (int)max_jitter) max_jitter = jitter;

	sum_jitter += jitter;
    }

    avg_jitter = (sum_jitter) / (strm_data->counter - 1);

    if (max_jitter < WARN_JITTER_USEC) {
	PJ_LOG(3,(THIS_FILE, 
		  "   Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
		  min_jitter/1000, min_jitter%1000, 
		  avg_jitter/1000, avg_jitter%1000,
		  max_jitter/1000, max_jitter%1000));
    } else {
	test_data->has_error = 1;
	PJ_LOG(2,(THIS_FILE, 
		  "   Jitter: min=%d.%03dms, avg=%d.%03dms, max=%d.%03dms",
		  min_jitter/1000, min_jitter%1000, 
		  avg_jitter/1000, avg_jitter%1000,
		  max_jitter/1000, max_jitter%1000));
    }
}


static int perform_test(int dev_id, pjmedia_dir dir,
		        unsigned clock_rate, unsigned samples_per_frame, 
			unsigned nchannel, int verbose)
{
    pj_status_t status = PJ_SUCCESS;
    pjmedia_snd_stream *strm;
    struct test_data test_data;
    pjmedia_snd_stream_info si;


    /*
     * Init test parameters
     */
    pj_bzero(&test_data, sizeof(test_data));
    test_data.dir = dir;
    test_data.clock_rate = clock_rate;
    test_data.samples_per_frame = samples_per_frame;
    test_data.channel_count = nchannel;

    /*
     * Open device.
     */
    if (dir == PJMEDIA_DIR_CAPTURE) {
	status = pjmedia_snd_open_rec( dev_id, clock_rate, nchannel,
				       samples_per_frame, 16, &rec_cb, 
				       &test_data, &strm);
    } else if (dir == PJMEDIA_DIR_PLAYBACK) {
	status = pjmedia_snd_open_player( dev_id, clock_rate, nchannel,
					  samples_per_frame, 16, &play_cb, 
					  &test_data, &strm);
    } else {
	status = pjmedia_snd_open( dev_id, dev_id, clock_rate, nchannel,
				   samples_per_frame, 16, &rec_cb, &play_cb, 
				   &test_data, &strm);
    }
    
    if (status != PJ_SUCCESS) {
        app_perror("Unable to open device for capture", status);
        return status;
    }

    pjmedia_snd_stream_get_info(strm, &si);
    if (si.play_id >= 0) {
	PJ_LOG(3,(THIS_FILE, "Testing playback device %s", 
		  pjmedia_snd_get_dev_info(si.play_id)->name));
    }
    if (si.rec_id >= 0) {
	PJ_LOG(3,(THIS_FILE, "Testing capture device %s", 
		  pjmedia_snd_get_dev_info(si.rec_id)->name));
    }

    /* Sleep for a while to let sound device "settles" */
    pj_thread_sleep(200);


    /*
     * Start the stream.
     */
    status = pjmedia_snd_stream_start(strm);
    if (status != PJ_SUCCESS) {
        app_perror("Unable to start capture stream", status);
        return status;
    }

    PJ_LOG(3,(THIS_FILE,
	      " Please wait while test is in progress (~%d secs)..",
	      (DURATION+SKIP_DURATION)/1000));

    /* Let the stream runs for few msec/sec to get stable result.
     * (capture normally begins with frames available simultaneously).
     */
    pj_thread_sleep(SKIP_DURATION);


    /* Begin gather data */
    test_data.running = 1;

    /* 
     * Let the test runs for a while.
     */
    pj_thread_sleep(DURATION);


    /*
     * Close stream.
     */
    test_data.running = 0;
    pjmedia_snd_stream_close(strm);


    /* 
     * Print results.
     */
    PJ_LOG(3,(THIS_FILE, " Dumping results:"));

    PJ_LOG(3,(THIS_FILE, "  Parameters: clock rate=%dHz, %d samples/frame",
	      clock_rate, samples_per_frame));

    if (dir & PJMEDIA_DIR_PLAYBACK)
	print_stream_data("Playback", &test_data, &test_data.playback_data, 
			  verbose);
    if (dir & PJMEDIA_DIR_CAPTURE)
	print_stream_data("Capture", &test_data, &test_data.capture_data, 
			   verbose);

    /* Check drifting */
    if (dir == PJMEDIA_DIR_CAPTURE_PLAYBACK) {
	int end_diff, start_diff, drift;

	end_diff = test_data.capture_data.last_timestamp -
		   test_data.playback_data.last_timestamp;
	start_diff = test_data.capture_data.first_timestamp-
		      test_data.playback_data.first_timestamp;
	drift = end_diff - start_diff;

	PJ_LOG(3,(THIS_FILE, "  Checking for clock drifts:"));

	/* Allow one frame tolerance for clock drift detection */
	if (drift < (int)samples_per_frame) {
	    PJ_LOG(3,(THIS_FILE, "   No clock drifts is detected"));
	} else {
	    const char *which = (drift<0 ? "slower" : "faster");
	    unsigned msec_dur;

	    if (drift < 0) drift = -drift;


	    msec_dur = (test_data.capture_data.last_timestamp - 
		       test_data.capture_data.first_timestamp) * 1000 /
		       test_data.clock_rate;

	    PJ_LOG(2,(THIS_FILE, 
		      "   Sound capture is %d samples %s than playback "
		      "at the end of the test (average is %d samples"
		      " per second)",
		      drift, which, 
		      drift * 1000 / msec_dur));

	}
    }

    if (test_data.has_error == 0) {
	PJ_LOG(3,(THIS_FILE, " Test completed, sound device looks okay."));
	return 0;
    } else {
	PJ_LOG(2,(THIS_FILE, " Test completed with some warnings"));
	return 1;
    }
}


int main(int argc, char *argv[])
{
    pj_caching_pool cp;
    pjmedia_endpt *med_endpt;
    int id = -1, verbose = 0;
    int clock_rate = 8000;
    int frame = -1;
    int channel = 1;
    struct pj_getopt_option long_options[] = {
	{ "id",	     1, 0, 'i' },
	{ "rate",    1, 0, 'r' },
	{ "frame",   1, 0, 'f' },
	{ "channel", 1, 0, 'n' },
	{ "verbose", 0, 0, 'v' },
	{ "help",    0, 0, 'h' },
	{ NULL, 0, 0, 0 }
    };
    int c, option_index;
    

    pj_status_t status;

    /* Init pjlib */
    status = pj_init();
    PJ_ASSERT_RETURN(status==PJ_SUCCESS, 1);
    
    /* Must create a pool factory before we can allocate any memory. */
    pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);

    /* 
     * Initialize media endpoint.
     * This will implicitly initialize PJMEDIA too.
     */
    status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);

    /* Print devices */
    enum_devices();

    /* Parse options */
    pj_optind = 0;
    while((c=pj_getopt_long(argc,argv, "i:r:f:n:vh", 
			    long_options, &option_index))!=-1) 
    {
	switch (c) {
	case 'i':
	    id = atoi(pj_optarg);
	    break;
	case 'r':
	    clock_rate = atoi(pj_optarg);
	    break;
	case 'f':
	    frame = atoi(pj_optarg);
	    break;
	case 'n':
	    channel = atoi(pj_optarg);
	    break;
	case 'v':
	    verbose = 1;
	    break;
	case 'h':
	    puts(desc);
	    return 0;
	    break;
	default:
	    printf("Error: invalid options %s\n", argv[pj_optind-1]);
	    puts(desc);
	    return 1;
	}
    }

    if (pj_optind != argc) {
	printf("Error: invalid options\n");
	puts(desc);
	return 1;
    }

    if (!verbose)
	pj_log_set_level(3);

    if (frame == -1)
	frame = 10 * clock_rate / 1000;


    status = perform_test(id, PJMEDIA_DIR_CAPTURE_PLAYBACK, 
			  clock_rate, frame, channel, verbose);
    if (status != 0)
	return 1;

    
    return 0;
}


⌨️ 快捷键说明

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