123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- /*
- * Copyright (C) 2008-2011 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
- */
- /* See http://trac.pjsip.org/repos/wiki/MeasuringSoundLatency on
- * how to use this program.
- */
- #include <pjmedia.h>
- #include <pjlib.h>
- #include <stdio.h>
- #define THIS_FILE "lacency.c"
- /* Util to display the error message for the specified error code */
- static int app_perror( const char *sender, const char *title,
- pj_status_t status)
- {
- char errmsg[PJ_ERR_MSG_SIZE];
- PJ_UNUSED_ARG(sender);
- pj_strerror(status, errmsg, sizeof(errmsg));
- printf("%s: %s [code=%d]\n", title, errmsg, status);
- return 1;
- }
- /*
- * Find out latency
- */
- static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
- {
- pjmedia_frame frm;
- short *buf;
- unsigned i, samples_per_frame;
- pj_size_t read, len;
- unsigned start_pos;
- pj_status_t status;
- unsigned lat_sum = 0,
- lat_cnt = 0,
- lat_min = 10000,
- lat_max = 0;
- samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
- frm.buf = pj_pool_alloc(pool, samples_per_frame * 2);
- frm.size = samples_per_frame * 2;
- len = pjmedia_wav_player_get_len(wav);
- buf = pj_pool_alloc(pool, len + samples_per_frame);
- read = 0;
- while (read < len/2) {
- status = pjmedia_port_get_frame(wav, &frm);
- if (status != PJ_SUCCESS)
- break;
- pjmedia_copy_samples(buf+read, (short*)frm.buf, samples_per_frame);
- read += samples_per_frame;
- }
- if (read < 2 * PJMEDIA_PIA_SRATE(&wav->info)) {
- puts("Error: too short");
- return -1;
- }
- start_pos = 0;
- while (start_pos < len/2 - PJMEDIA_PIA_SRATE(&wav->info)) {
- int max_signal = 0;
- unsigned max_signal_pos = start_pos;
- unsigned max_echo_pos = 0;
- unsigned pos;
- unsigned lat;
- /* Get the largest signal in the next 0.7s */
- for (i=start_pos; i<start_pos + PJMEDIA_PIA_SRATE(&wav->info) * 700 / 1000; ++i) {
- if (abs(buf[i]) > max_signal) {
- max_signal = abs(buf[i]);
- max_signal_pos = i;
- }
- }
- /* Advance 10ms from max_signal_pos */
- pos = max_signal_pos + 10 * PJMEDIA_PIA_SRATE(&wav->info) / 1000;
- /* Get the largest signal in the next 500ms */
- max_signal = 0;
- max_echo_pos = pos;
- for (i=pos; i<pos+PJMEDIA_PIA_SRATE(&wav->info)/2; ++i) {
- if (abs(buf[i]) > max_signal) {
- max_signal = abs(buf[i]);
- max_echo_pos = i;
- }
- }
- lat = (max_echo_pos - max_signal_pos) * 1000 / PJMEDIA_PIA_SRATE(&wav->info);
-
- #if 0
- printf("Latency = %u\n", lat);
- #endif
- lat_sum += lat;
- lat_cnt++;
- if (lat < lat_min)
- lat_min = lat;
- if (lat > lat_max)
- lat_max = lat;
- /* Advance next loop */
- start_pos += PJMEDIA_PIA_SRATE(&wav->info);
- }
- if (lat_cnt)
- printf("Latency average = %u\n", lat_sum / lat_cnt);
- printf("Latency minimum = %u\n", lat_min);
- printf("Latency maximum = %u\n", lat_max);
- printf("Number of data = %u\n", lat_cnt);
- return 0;
- }
- /*
- * main()
- */
- int main(int argc, char *argv[])
- {
- enum { NSAMPLES = 160, COUNT=100 };
- pj_caching_pool cp;
- pj_pool_t *pool;
- pjmedia_port *wav;
- pj_status_t status;
- /* Verify cmd line arguments. */
- if (argc != 2) {
- puts("Error: missing argument(s)");
- puts("Usage: latency REV.WAV");
- return 1;
- }
- pj_log_set_level(0);
- status = pj_init();
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
- pool = pj_pool_create( &cp.factory, /* pool factory */
- "wav", /* pool name. */
- 4000, /* init size */
- 4000, /* increment size */
- NULL /* callback on error */
- );
- status = pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
- &pjmedia_strerror);
- pj_assert(status == PJ_SUCCESS);
- /* Wav */
- status = pjmedia_wav_player_port_create( pool, /* memory pool */
- argv[1], /* file to play */
- 0, /* use default ptime*/
- 0, /* flags */
- 0, /* default buffer */
- &wav /* returned port */
- );
- if (status != PJ_SUCCESS) {
- app_perror(THIS_FILE, argv[1], status);
- return 1;
- }
- status = calculate_latency(pool, wav);
- if (status != PJ_SUCCESS)
- return 1;
- status = pjmedia_port_destroy( wav );
- PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
- pj_pool_release( pool );
- pj_caching_pool_destroy( &cp );
- pj_shutdown();
- /* Done. */
- return 0;
- }
|