latency.c 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
  3. * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
  4. *
  5. * This program is free software; you can redistribute it and/or modify
  6. * it under the terms of the GNU General Public License as published by
  7. * the Free Software Foundation; either version 2 of the License, or
  8. * (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU General Public License
  16. * along with this program; if not, write to the Free Software
  17. * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  18. */
  19. /* See http://trac.pjsip.org/repos/wiki/MeasuringSoundLatency on
  20. * how to use this program.
  21. */
  22. #include <pjmedia.h>
  23. #include <pjlib.h>
  24. #include <stdio.h>
  25. #define THIS_FILE "lacency.c"
  26. /* Util to display the error message for the specified error code */
  27. static int app_perror( const char *sender, const char *title,
  28. pj_status_t status)
  29. {
  30. char errmsg[PJ_ERR_MSG_SIZE];
  31. PJ_UNUSED_ARG(sender);
  32. pj_strerror(status, errmsg, sizeof(errmsg));
  33. printf("%s: %s [code=%d]\n", title, errmsg, status);
  34. return 1;
  35. }
  36. /*
  37. * Find out latency
  38. */
  39. static int calculate_latency(pj_pool_t *pool, pjmedia_port *wav)
  40. {
  41. pjmedia_frame frm;
  42. short *buf;
  43. unsigned i, samples_per_frame;
  44. pj_size_t read, len;
  45. unsigned start_pos;
  46. pj_status_t status;
  47. unsigned lat_sum = 0,
  48. lat_cnt = 0,
  49. lat_min = 10000,
  50. lat_max = 0;
  51. samples_per_frame = PJMEDIA_PIA_SPF(&wav->info);
  52. frm.buf = pj_pool_alloc(pool, samples_per_frame * 2);
  53. frm.size = samples_per_frame * 2;
  54. len = pjmedia_wav_player_get_len(wav);
  55. buf = pj_pool_alloc(pool, len + samples_per_frame);
  56. read = 0;
  57. while (read < len/2) {
  58. status = pjmedia_port_get_frame(wav, &frm);
  59. if (status != PJ_SUCCESS)
  60. break;
  61. pjmedia_copy_samples(buf+read, (short*)frm.buf, samples_per_frame);
  62. read += samples_per_frame;
  63. }
  64. if (read < 2 * PJMEDIA_PIA_SRATE(&wav->info)) {
  65. puts("Error: too short");
  66. return -1;
  67. }
  68. start_pos = 0;
  69. while (start_pos < len/2 - PJMEDIA_PIA_SRATE(&wav->info)) {
  70. int max_signal = 0;
  71. unsigned max_signal_pos = start_pos;
  72. unsigned max_echo_pos = 0;
  73. unsigned pos;
  74. unsigned lat;
  75. /* Get the largest signal in the next 0.7s */
  76. for (i=start_pos; i<start_pos + PJMEDIA_PIA_SRATE(&wav->info) * 700 / 1000; ++i) {
  77. if (abs(buf[i]) > max_signal) {
  78. max_signal = abs(buf[i]);
  79. max_signal_pos = i;
  80. }
  81. }
  82. /* Advance 10ms from max_signal_pos */
  83. pos = max_signal_pos + 10 * PJMEDIA_PIA_SRATE(&wav->info) / 1000;
  84. /* Get the largest signal in the next 500ms */
  85. max_signal = 0;
  86. max_echo_pos = pos;
  87. for (i=pos; i<pos+PJMEDIA_PIA_SRATE(&wav->info)/2; ++i) {
  88. if (abs(buf[i]) > max_signal) {
  89. max_signal = abs(buf[i]);
  90. max_echo_pos = i;
  91. }
  92. }
  93. lat = (max_echo_pos - max_signal_pos) * 1000 / PJMEDIA_PIA_SRATE(&wav->info);
  94. #if 0
  95. printf("Latency = %u\n", lat);
  96. #endif
  97. lat_sum += lat;
  98. lat_cnt++;
  99. if (lat < lat_min)
  100. lat_min = lat;
  101. if (lat > lat_max)
  102. lat_max = lat;
  103. /* Advance next loop */
  104. start_pos += PJMEDIA_PIA_SRATE(&wav->info);
  105. }
  106. if (lat_cnt)
  107. printf("Latency average = %u\n", lat_sum / lat_cnt);
  108. printf("Latency minimum = %u\n", lat_min);
  109. printf("Latency maximum = %u\n", lat_max);
  110. printf("Number of data = %u\n", lat_cnt);
  111. return 0;
  112. }
  113. /*
  114. * main()
  115. */
  116. int main(int argc, char *argv[])
  117. {
  118. enum { NSAMPLES = 160, COUNT=100 };
  119. pj_caching_pool cp;
  120. pj_pool_t *pool;
  121. pjmedia_port *wav;
  122. pj_status_t status;
  123. /* Verify cmd line arguments. */
  124. if (argc != 2) {
  125. puts("Error: missing argument(s)");
  126. puts("Usage: latency REV.WAV");
  127. return 1;
  128. }
  129. pj_log_set_level(0);
  130. status = pj_init();
  131. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  132. pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
  133. pool = pj_pool_create( &cp.factory, /* pool factory */
  134. "wav", /* pool name. */
  135. 4000, /* init size */
  136. 4000, /* increment size */
  137. NULL /* callback on error */
  138. );
  139. status = pj_register_strerror(PJMEDIA_ERRNO_START, PJ_ERRNO_SPACE_SIZE,
  140. &pjmedia_strerror);
  141. pj_assert(status == PJ_SUCCESS);
  142. /* Wav */
  143. status = pjmedia_wav_player_port_create( pool, /* memory pool */
  144. argv[1], /* file to play */
  145. 0, /* use default ptime*/
  146. 0, /* flags */
  147. 0, /* default buffer */
  148. &wav /* returned port */
  149. );
  150. if (status != PJ_SUCCESS) {
  151. app_perror(THIS_FILE, argv[1], status);
  152. return 1;
  153. }
  154. status = calculate_latency(pool, wav);
  155. if (status != PJ_SUCCESS)
  156. return 1;
  157. status = pjmedia_port_destroy( wav );
  158. PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
  159. pj_pool_release( pool );
  160. pj_caching_pool_destroy( &cp );
  161. pj_shutdown();
  162. /* Done. */
  163. return 0;
  164. }