WARNING: The online documentation has moved to https://docs.pjsip.org.

Visit the new documentation at https://docs.pjsip.org:

BLOG | DOCUMENTATION | GITHUB

Home --> Documentations --> PJMEDIA Reference

Samples: Remote Streaming

This example mainly demonstrates how to stream media file to remote peer using RTP.

This file is pjsip-apps/src/samples/streamutil.c

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
20
32#include <pjlib.h>
33#include <pjlib-util.h>
34#include <pjmedia.h>
35#include <pjmedia-codec.h>
37
38#include <stdlib.h> /* atoi() */
39#include <stdio.h>
40
41#include "util.h"
42
43/* An experimental feature to add multicast option to this app for providing
44 * the capability to send IP datagrams from a single source to more than
45 * one receivers.
46 */
47#define HAVE_MULTICAST 1
48
49static const char *desc =
50 " streamutil \n"
51 " \n"
52 " PURPOSE: \n"
53 " Demonstrate how to use pjmedia stream component to transmit/receive \n"
54 " RTP packets to/from sound device. \n"
55 "\n"
56 "\n"
57 " USAGE: \n"
58 " streamutil [options] \n"
59 "\n"
60 "\n"
61 " Options:\n"
62 " --codec=CODEC Set the codec name. \n"
63 " --local-port=PORT Set local RTP port (default=4000) \n"
64 " --remote=IP:PORT Set the remote peer. If this option is set, \n"
65 " the program will transmit RTP audio to the \n"
66 " specified address. (default: recv only) \n"
67#if HAVE_MULTICAST
68 " --mcast-add=IP Joins the multicast group as specified by \n"
69 " the address. Sample usage: \n"
70 " Sender: \n"
71 " streamutil --remote=[multicast_addr]:[port] \n"
72 " Receivers: \n"
73 " streamutil --local-port=[port] \n"
74 " --mcast-add=[multicast_addr] \n"
75#endif
76 " --play-file=WAV Send audio from the WAV file instead of from \n"
77 " the sound device. \n"
78 " --record-file=WAV Record incoming audio to WAV file instead of \n"
79 " playing it to sound device. \n"
80 " --send-recv Set stream direction to bidirectional. \n"
81 " --send-only Set stream direction to send only \n"
82 " --recv-only Set stream direction to recv only (default) \n"
83
84#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
85 " --use-srtp[=NAME] Enable SRTP with crypto suite NAME \n"
86 " e.g: AES_CM_128_HMAC_SHA1_80 (default), \n"
87 " AES_CM_128_HMAC_SHA1_32 \n"
88 " Use this option along with the TX & RX keys, \n"
89 " formated of 60 hex digits (e.g: E148DA..) \n"
90 " --srtp-tx-key SRTP key for transmiting \n"
91 " --srtp-rx-key SRTP key for receiving \n"
92 " --srtp-dtls-client Use DTLS for SRTP keying, as DTLS client \n"
93 " --srtp-dtls-server Use DTLS for SRTP keying, as DTLS server \n"
94#endif
95
96 "\n"
97;
98
99
100
101
102#define THIS_FILE "stream.c"
103
104
105
106/* Prototype */
107static void print_stream_stat(pjmedia_stream *stream,
108 const pjmedia_codec_param *codec_param);
109
110/* Hexa string to octet array */
111int my_hex_string_to_octet_string(char *raw, char *hex, int len)
112{
113 int i;
114 for (i = 0; i < len; i+=2) {
115 int tmp;
116 if (i+1 >= len || !pj_isxdigit(hex[i]) || !pj_isxdigit(hex[i+1]))
117 return i;
118 tmp = pj_hex_digit_to_val((unsigned char)hex[i]) << 4;
119 tmp |= pj_hex_digit_to_val((unsigned char)hex[i+1]);
120 raw[i/2] = (char)(tmp & 0xFF);
121 }
122 return len;
123}
124
125/*
126 * Register all codecs.
127 */
128static pj_status_t init_codecs(pjmedia_endpt *med_endpt)
129{
130 return pjmedia_codec_register_audio_codecs(med_endpt, NULL);
131}
132
133
134/*
135 * Create stream based on the codec, dir, remote address, etc.
136 */
137static pj_status_t create_stream( pj_pool_t *pool,
138 pjmedia_endpt *med_endpt,
139 const pjmedia_codec_info *codec_info,
140 pjmedia_dir dir,
141 pj_uint16_t local_port,
142 const pj_sockaddr_in *rem_addr,
143 pj_bool_t mcast,
144 const pj_sockaddr_in *mcast_addr,
145#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
146 pj_bool_t use_srtp,
147 const pj_str_t *crypto_suite,
148 const pj_str_t *srtp_tx_key,
149 const pj_str_t *srtp_rx_key,
150 pj_bool_t is_dtls_client,
151 pj_bool_t is_dtls_server,
152#endif
153 pjmedia_stream **p_stream )
154{
156 pjmedia_transport *transport = NULL;
157 pj_status_t status;
158#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
159 pjmedia_transport *srtp_tp = NULL;
160#endif
161
162
163 /* Reset stream info. */
164 pj_bzero(&info, sizeof(info));
165
166
167 /* Initialize stream info formats */
169 info.dir = dir;
170 pj_memcpy(&info.fmt, codec_info, sizeof(pjmedia_codec_info));
171 info.tx_pt = codec_info->pt;
172 info.rx_pt = codec_info->pt;
173 info.ssrc = pj_rand();
174
175#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR
176 /* Set default RTCP XR enabled/disabled */
177 info.rtcp_xr_enabled = PJ_TRUE;
178#endif
179
180 /* Copy remote address */
181 pj_memcpy(&info.rem_addr, rem_addr, sizeof(pj_sockaddr_in));
182
183 /* If remote address is not set, set to an arbitrary address
184 * (otherwise stream will assert).
185 */
186 if (info.rem_addr.addr.sa_family == 0) {
187 const pj_str_t addr = pj_str("127.0.0.1");
188 pj_sockaddr_in_init(&info.rem_addr.ipv4, &addr, 0);
189 }
190
191 pj_sockaddr_cp(&info.rem_rtcp, &info.rem_addr);
194
195 if (mcast) {
197 int reuse = 1;
198
199 pj_bzero(&si, sizeof(pjmedia_sock_info));
201
202 /* Create RTP socket */
203 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0,
204 &si.rtp_sock);
205 if (status != PJ_SUCCESS)
206 return status;
207
209 pj_SO_REUSEADDR(), &reuse, sizeof(reuse));
210 if (status != PJ_SUCCESS)
211 return status;
212
213 /* Bind RTP socket */
215 NULL, local_port);
216 if (status != PJ_SUCCESS)
217 return status;
218
219 status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name,
221 if (status != PJ_SUCCESS)
222 return status;
223
224 /* Create RTCP socket */
225 status = pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0,
226 &si.rtcp_sock);
227 if (status != PJ_SUCCESS)
228 return status;
229
231 pj_SO_REUSEADDR(), &reuse, sizeof(reuse));
232 if (status != PJ_SUCCESS)
233 return status;
234
235 /* Bind RTCP socket */
237 NULL, local_port+1);
238 if (status != PJ_SUCCESS)
239 return status;
240
241 status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name,
243 if (status != PJ_SUCCESS)
244 return status;
245
246#ifdef HAVE_MULTICAST
247 {
248 unsigned char loop;
249 struct pj_ip_mreq imr;
250
251 pj_memset(&imr, 0, sizeof(struct pj_ip_mreq));
252 imr.imr_multiaddr.s_addr = mcast_addr->sin_addr.s_addr;
253 imr.imr_interface.s_addr = pj_htonl(PJ_INADDR_ANY);
256 &imr, sizeof(struct pj_ip_mreq));
257 if (status != PJ_SUCCESS)
258 return status;
259
262 &imr, sizeof(struct pj_ip_mreq));
263 if (status != PJ_SUCCESS)
264 return status;
265
266 /* Disable local reception of local sent packets */
267 loop = 0;
269 pj_IP_MULTICAST_LOOP(), &loop, sizeof(loop));
271 pj_IP_MULTICAST_LOOP(), &loop, sizeof(loop));
272 }
273#endif
274
275 /* Create media transport from existing sockets */
276 status = pjmedia_transport_udp_attach( med_endpt, NULL, &si,
278 if (status != PJ_SUCCESS)
279 return status;
280
281 } else {
282 /* Create media transport */
283 status = pjmedia_transport_udp_create(med_endpt, NULL, local_port,
284 0, &transport);
285 if (status != PJ_SUCCESS)
286 return status;
287 }
288
289#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
290 /* Check if SRTP enabled */
291 if (use_srtp) {
292 status = pjmedia_transport_srtp_create(med_endpt, transport,
293 NULL, &srtp_tp);
294 if (status != PJ_SUCCESS)
295 return status;
296
297 if (is_dtls_client || is_dtls_server) {
298 char fp[128];
299 pj_size_t fp_len = sizeof(fp);
301
302 pjmedia_transport_srtp_dtls_get_fingerprint(srtp_tp, "SHA-256", fp, &fp_len);
303 PJ_LOG(3, (THIS_FILE, "Local cert fingerprint: %s", fp));
304
305 pj_bzero(&dtls_param, sizeof(dtls_param));
306 pj_sockaddr_cp(&dtls_param.rem_addr, rem_addr);
307 pj_sockaddr_cp(&dtls_param.rem_rtcp, rem_addr);
308 dtls_param.is_role_active = is_dtls_client;
309
310 status = pjmedia_transport_srtp_dtls_start_nego(srtp_tp, &dtls_param);
311 if (status != PJ_SUCCESS)
312 return status;
313 } else {
314 pjmedia_srtp_crypto tx_plc, rx_plc;
315
316 pj_bzero(&tx_plc, sizeof(pjmedia_srtp_crypto));
317 pj_bzero(&rx_plc, sizeof(pjmedia_srtp_crypto));
318
319 tx_plc.key = *srtp_tx_key;
320 tx_plc.name = *crypto_suite;
321 rx_plc.key = *srtp_rx_key;
322 rx_plc.name = *crypto_suite;
323
324 status = pjmedia_transport_srtp_start(srtp_tp, &tx_plc, &rx_plc);
325 if (status != PJ_SUCCESS)
326 return status;
327 }
328
329 transport = srtp_tp;
330 }
331#endif
332
333 /* Now that the stream info is initialized, we can create the
334 * stream.
335 */
336
337 status = pjmedia_stream_create( med_endpt, pool, &info,
338 transport,
339 NULL, p_stream);
340
341 if (status != PJ_SUCCESS) {
342 app_perror(THIS_FILE, "Error creating stream", status);
343 pjmedia_transport_close(transport);
344 return status;
345 }
346
347 /* Start media transport */
348 pjmedia_transport_media_start(transport, 0, 0, 0, 0);
349
350
351 return PJ_SUCCESS;
352}
353
354
355/*
356 * usage()
357 */
358static void usage()
359{
360 puts(desc);
361}
362
363/*
364 * main()
365 */
366int main(int argc, char *argv[])
367{
369 pjmedia_endpt *med_endpt;
370 pj_pool_t *pool;
371 pjmedia_port *rec_file_port = NULL, *play_file_port = NULL;
372 pjmedia_master_port *master_port = NULL;
373 pjmedia_snd_port *snd_port = NULL;
374 pjmedia_stream *stream = NULL;
375 pjmedia_port *stream_port;
376 char tmp[10];
377 char addr[PJ_INET_ADDRSTRLEN];
378 pj_status_t status;
379
380#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
381 /* SRTP variables */
382 pj_bool_t use_srtp = PJ_FALSE;
383 char tmp_tx_key[64];
384 char tmp_rx_key[64];
385 pj_str_t srtp_tx_key = {NULL, 0};
386 pj_str_t srtp_rx_key = {NULL, 0};
387 pj_str_t srtp_crypto_suite = {NULL, 0};
388 pj_bool_t is_dtls_client = PJ_FALSE;
389 pj_bool_t is_dtls_server = PJ_FALSE;
390 int tmp_key_len;
391#endif
392
393 /* Default values */
394 const pjmedia_codec_info *codec_info;
395 pjmedia_codec_param codec_param;
397 pj_sockaddr_in remote_addr;
398 pj_sockaddr_in mcast_addr;
399 pj_uint16_t local_port = 4000;
400 char *codec_id = NULL;
401 char *rec_file = NULL;
402 char *play_file = NULL;
403 int mcast = 0;
404
405 enum {
406 OPT_CODEC = 'c',
407 OPT_LOCAL_PORT = 'p',
408 OPT_REMOTE = 'r',
409 OPT_MCAST = 'm',
410 OPT_PLAY_FILE = 'w',
411 OPT_RECORD_FILE = 'R',
412 OPT_SEND_RECV = 'b',
413 OPT_SEND_ONLY = 's',
414 OPT_RECV_ONLY = 'i',
415#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
416 OPT_USE_SRTP = 'S',
417#endif
418 OPT_SRTP_TX_KEY = 'x',
419 OPT_SRTP_RX_KEY = 'y',
420 OPT_SRTP_DTLS_CLIENT = 'd',
421 OPT_SRTP_DTLS_SERVER = 'D',
422 OPT_HELP = 'h',
423 };
424
425 struct pj_getopt_option long_options[] = {
426 { "codec", 1, 0, OPT_CODEC },
427 { "local-port", 1, 0, OPT_LOCAL_PORT },
428 { "remote", 1, 0, OPT_REMOTE },
429 { "mcast-add", 1, 0, OPT_MCAST },
430 { "play-file", 1, 0, OPT_PLAY_FILE },
431 { "record-file", 1, 0, OPT_RECORD_FILE },
432 { "send-recv", 0, 0, OPT_SEND_RECV },
433 { "send-only", 0, 0, OPT_SEND_ONLY },
434 { "recv-only", 0, 0, OPT_RECV_ONLY },
435#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
436 { "use-srtp", 2, 0, OPT_USE_SRTP },
437 { "srtp-tx-key", 1, 0, OPT_SRTP_TX_KEY },
438 { "srtp-rx-key", 1, 0, OPT_SRTP_RX_KEY },
439 { "srtp-dtls-client", 0, 0, OPT_SRTP_DTLS_CLIENT },
440 { "srtp-dtls-server", 0, 0, OPT_SRTP_DTLS_SERVER },
441#endif
442 { "help", 0, 0, OPT_HELP },
443 { NULL, 0, 0, 0 },
444 };
445
446 int c;
447 int option_index;
448
449
450 pj_bzero(&remote_addr, sizeof(remote_addr));
451
452
453 /* init PJLIB : */
454 status = pj_init();
455 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
456
457
458 /* Parse arguments */
459 pj_optind = 0;
460 while((c=pj_getopt_long(argc,argv, "h", long_options, &option_index))!=-1) {
461
462 switch (c) {
463 case OPT_CODEC:
464 codec_id = pj_optarg;
465 break;
466
467 case OPT_LOCAL_PORT:
468 local_port = (pj_uint16_t) atoi(pj_optarg);
469 if (local_port < 1) {
470 printf("Error: invalid local port %s\n", pj_optarg);
471 return 1;
472 }
473 break;
474
475 case OPT_REMOTE:
476 {
477 pj_str_t ip = pj_str(strtok(pj_optarg, ":"));
478 pj_uint16_t port = (pj_uint16_t) atoi(strtok(NULL, ":"));
479
480 status = pj_sockaddr_in_init(&remote_addr, &ip, port);
481 if (status != PJ_SUCCESS) {
482 app_perror(THIS_FILE, "Invalid remote address", status);
483 return 1;
484 }
485 }
486 break;
487
488 case OPT_MCAST:
489 {
490 pj_str_t ip = pj_str(pj_optarg);
491
492 mcast = 1;
493 status = pj_sockaddr_in_init(&mcast_addr, &ip, 0);
494 if (status != PJ_SUCCESS) {
495 app_perror(THIS_FILE, "Invalid mcast address", status);
496 return 1;
497 }
498 }
499 break;
500
501 case OPT_PLAY_FILE:
502 play_file = pj_optarg;
503 break;
504
505 case OPT_RECORD_FILE:
506 rec_file = pj_optarg;
507 break;
508
509 case OPT_SEND_RECV:
511 break;
512
513 case OPT_SEND_ONLY:
515 break;
516
517 case OPT_RECV_ONLY:
519 break;
520
521#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
522 case OPT_USE_SRTP:
523 use_srtp = PJ_TRUE;
524 if (pj_optarg) {
525 pj_strset(&srtp_crypto_suite, pj_optarg, strlen(pj_optarg));
526 } else {
527 srtp_crypto_suite = pj_str("AES_CM_128_HMAC_SHA1_80");
528 }
529 break;
530
531 case OPT_SRTP_TX_KEY:
532 tmp_key_len = my_hex_string_to_octet_string(tmp_tx_key, pj_optarg,
533 (int)strlen(pj_optarg));
534 pj_strset(&srtp_tx_key, tmp_tx_key, tmp_key_len/2);
535 break;
536
537 case OPT_SRTP_RX_KEY:
538 tmp_key_len = my_hex_string_to_octet_string(tmp_rx_key, pj_optarg,
539 (int)strlen(pj_optarg));
540 pj_strset(&srtp_rx_key, tmp_rx_key, tmp_key_len/2);
541 break;
542 case OPT_SRTP_DTLS_CLIENT:
543 is_dtls_client = PJ_TRUE;
544 if (is_dtls_server) {
545 printf("Error: Cannot be as both DTLS server & client\n");
546 return 1;
547 }
548 break;
549 case OPT_SRTP_DTLS_SERVER:
550 is_dtls_server = PJ_TRUE;
551 if (is_dtls_client) {
552 printf("Error: Cannot be as both DTLS server & client\n");
553 return 1;
554 }
555 break;
556#endif
557
558 case OPT_HELP:
559 usage();
560 return 1;
561
562 default:
563 printf("Invalid options %s\n", argv[pj_optind]);
564 return 1;
565 }
566
567 }
568
569
570 /* Verify arguments. */
571 if (dir & PJMEDIA_DIR_ENCODING
572#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
573 || is_dtls_client || is_dtls_server
574#endif
575 ) {
576 if (remote_addr.sin_addr.s_addr == 0) {
577 printf("Error: remote address must be set\n");
578 return 1;
579 }
580 }
581
582 if (play_file != NULL && dir != PJMEDIA_DIR_ENCODING) {
583 printf("Direction is set to --send-only because of --play-file\n");
585 }
586
587#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
588 /* SRTP validation */
589 if (use_srtp) {
590 if (!is_dtls_client && !is_dtls_server &&
591 (!srtp_tx_key.slen || !srtp_rx_key.slen))
592 {
593 printf("Error: Key for each SRTP stream direction must be set\n");
594 return 1;
595 }
596 }
597#endif
598
599 /* Must create a pool factory before we can allocate any memory. */
601
602 /*
603 * Initialize media endpoint.
604 * This will implicitly initialize PJMEDIA too.
605 */
606 status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
607 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
608
609 /* Create memory pool for application purpose */
610 pool = pj_pool_create( &cp.factory, /* pool factory */
611 "app", /* pool name. */
612 4000, /* init size */
613 4000, /* increment size */
614 NULL /* callback on error */
615 );
616
617
618 /* Register all supported codecs */
619 status = init_codecs(med_endpt);
620 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
621
622
623 /* Find which codec to use. */
624 if (codec_id) {
625 unsigned count = 1;
626 pj_str_t str_codec_id = pj_str(codec_id);
627 pjmedia_codec_mgr *codec_mgr = pjmedia_endpt_get_codec_mgr(med_endpt);
628 status = pjmedia_codec_mgr_find_codecs_by_id( codec_mgr,
629 &str_codec_id, &count,
630 &codec_info, NULL);
631 if (status != PJ_SUCCESS) {
632 printf("Error: unable to find codec %s\n", codec_id);
633 return 1;
634 }
635 } else {
636 /* Default to pcmu */
638 0, &codec_info);
639 }
640
641 /* Create event manager */
642 status = pjmedia_event_mgr_create(pool, 0, NULL);
643 if (status != PJ_SUCCESS)
644 goto on_exit;
645
646 /* Create stream based on program arguments */
647 status = create_stream(pool, med_endpt, codec_info, dir, local_port,
648 &remote_addr, mcast, &mcast_addr,
649#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
650 use_srtp, &srtp_crypto_suite,
651 &srtp_tx_key, &srtp_rx_key,
652 is_dtls_client, is_dtls_server,
653#endif
654 &stream);
655 if (status != PJ_SUCCESS)
656 goto on_exit;
657
658 /* Get codec default param for info */
660 pjmedia_endpt_get_codec_mgr(med_endpt),
661 codec_info,
662 &codec_param);
663 /* Should be ok, as create_stream() above succeeded */
664 pj_assert(status == PJ_SUCCESS);
665
666 /* Get the port interface of the stream */
667 status = pjmedia_stream_get_port( stream, &stream_port);
668 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
669
670
671 if (play_file) {
672 unsigned wav_ptime;
673
674 wav_ptime = PJMEDIA_PIA_PTIME(&stream_port->info);
675 status = pjmedia_wav_player_port_create(pool, play_file, wav_ptime,
676 0, -1, &play_file_port);
677 if (status != PJ_SUCCESS) {
678 app_perror(THIS_FILE, "Unable to use file", status);
679 goto on_exit;
680 }
681
682 status = pjmedia_master_port_create(pool, play_file_port, stream_port,
683 0, &master_port);
684 if (status != PJ_SUCCESS) {
685 app_perror(THIS_FILE, "Unable to create master port", status);
686 goto on_exit;
687 }
688
689 status = pjmedia_master_port_start(master_port);
690 if (status != PJ_SUCCESS) {
691 app_perror(THIS_FILE, "Error starting master port", status);
692 goto on_exit;
693 }
694
695 printf("Playing from WAV file %s..\n", play_file);
696
697 } else if (rec_file) {
698
699 status = pjmedia_wav_writer_port_create(pool, rec_file,
700 PJMEDIA_PIA_SRATE(&stream_port->info),
701 PJMEDIA_PIA_CCNT(&stream_port->info),
702 PJMEDIA_PIA_SPF(&stream_port->info),
703 PJMEDIA_PIA_BITS(&stream_port->info),
704 0, 0, &rec_file_port);
705 if (status != PJ_SUCCESS) {
706 app_perror(THIS_FILE, "Unable to use file", status);
707 goto on_exit;
708 }
709
710 status = pjmedia_master_port_create(pool, stream_port, rec_file_port,
711 0, &master_port);
712 if (status != PJ_SUCCESS) {
713 app_perror(THIS_FILE, "Unable to create master port", status);
714 goto on_exit;
715 }
716
717 status = pjmedia_master_port_start(master_port);
718 if (status != PJ_SUCCESS) {
719 app_perror(THIS_FILE, "Error starting master port", status);
720 goto on_exit;
721 }
722
723 printf("Recording to WAV file %s..\n", rec_file);
724
725 } else {
726
727 /* Create sound device port. */
729 status = pjmedia_snd_port_create(pool, -1, -1,
730 PJMEDIA_PIA_SRATE(&stream_port->info),
731 PJMEDIA_PIA_CCNT(&stream_port->info),
732 PJMEDIA_PIA_SPF(&stream_port->info),
733 PJMEDIA_PIA_BITS(&stream_port->info),
734 0, &snd_port);
735 else if (dir == PJMEDIA_DIR_ENCODING)
736 status = pjmedia_snd_port_create_rec(pool, -1,
737 PJMEDIA_PIA_SRATE(&stream_port->info),
738 PJMEDIA_PIA_CCNT(&stream_port->info),
739 PJMEDIA_PIA_SPF(&stream_port->info),
740 PJMEDIA_PIA_BITS(&stream_port->info),
741 0, &snd_port);
742 else
743 status = pjmedia_snd_port_create_player(pool, -1,
744 PJMEDIA_PIA_SRATE(&stream_port->info),
745 PJMEDIA_PIA_CCNT(&stream_port->info),
746 PJMEDIA_PIA_SPF(&stream_port->info),
747 PJMEDIA_PIA_BITS(&stream_port->info),
748 0, &snd_port);
749
750
751 if (status != PJ_SUCCESS) {
752 app_perror(THIS_FILE, "Unable to create sound port", status);
753 goto on_exit;
754 }
755
756 /* Connect sound port to stream */
757 status = pjmedia_snd_port_connect( snd_port, stream_port );
758 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
759
760 }
761
762 /* Start streaming */
764
765
766 /* Done */
767
768 if (dir == PJMEDIA_DIR_DECODING)
769 printf("Stream is active, dir is recv-only, local port is %d\n",
770 local_port);
771 else if (dir == PJMEDIA_DIR_ENCODING)
772 printf("Stream is active, dir is send-only, sending to %s:%d\n",
773 pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
774 sizeof(addr)),
775 pj_ntohs(remote_addr.sin_port));
776 else
777 printf("Stream is active, send/recv, local port is %d, "
778 "sending to %s:%d\n",
779 local_port,
780 pj_inet_ntop2(pj_AF_INET(), &remote_addr.sin_addr, addr,
781 sizeof(addr)),
782 pj_ntohs(remote_addr.sin_port));
783
784
785 for (;;) {
786
787 puts("");
788 puts("Commands:");
789 puts(" s Display media statistics");
790 puts(" q Quit");
791 puts("");
792
793 printf("Command: "); fflush(stdout);
794
795 if (fgets(tmp, sizeof(tmp), stdin) == NULL) {
796 puts("EOF while reading stdin, will quit now..");
797 break;
798 }
799
800 if (tmp[0] == 's')
801 print_stream_stat(stream, &codec_param);
802 else if (tmp[0] == 'q')
803 break;
804
805 }
806
807
808
809 /* Start deinitialization: */
810on_exit:
811
812 /* Destroy sound device */
813 if (snd_port) {
814 pjmedia_snd_port_destroy( snd_port );
815 PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
816 }
817
818 /* If there is master port, then we just need to destroy master port
819 * (it will recursively destroy upstream and downstream ports, which
820 * in this case are file_port and stream_port).
821 */
822 if (master_port) {
824 play_file_port = NULL;
825 stream = NULL;
826 }
827
828 /* Destroy stream */
829 if (stream) {
831
834
837 }
838
839 /* Destroy file ports */
840 if (play_file_port)
841 pjmedia_port_destroy( play_file_port );
842 if (rec_file_port)
843 pjmedia_port_destroy( rec_file_port );
844
845 /* Destroy event manager */
847
848 /* Release application pool */
849 pj_pool_release( pool );
850
851 /* Destroy media endpoint. */
852 pjmedia_endpt_destroy( med_endpt );
853
854 /* Destroy pool factory */
856
857 /* Shutdown PJLIB */
858 pj_shutdown();
859
860
861 return (status == PJ_SUCCESS) ? 0 : 1;
862}
863
864
865
866
867static const char *good_number(char *buf, pj_int32_t val)
868{
869 if (val < 1000) {
870 pj_ansi_sprintf(buf, "%d", val);
871 } else if (val < 1000000) {
872 pj_ansi_sprintf(buf, "%d.%dK",
873 val / 1000,
874 (val % 1000) / 100);
875 } else {
876 pj_ansi_sprintf(buf, "%d.%02dM",
877 val / 1000000,
878 (val % 1000000) / 10000);
879 }
880
881 return buf;
882}
883
884
885#define SAMPLES_TO_USEC(usec, samples, clock_rate) \
886 do { \
887 if (samples <= 4294) \
888 usec = samples * 1000000 / clock_rate; \
889 else { \
890 usec = samples * 1000 / clock_rate; \
891 usec *= 1000; \
892 } \
893 } while(0)
894
895#define PRINT_VOIP_MTC_VAL(s, v) \
896 if (v == 127) \
897 sprintf(s, "(na)"); \
898 else \
899 sprintf(s, "%d", v)
900
901
902/*
903 * Print stream statistics
904 */
905static void print_stream_stat(pjmedia_stream *stream,
906 const pjmedia_codec_param *codec_param)
907{
908 char duration[80], last_update[80];
909 char bps[16], ipbps[16], packets[16], bytes[16], ipbytes[16];
910 pjmedia_port *port;
912 pj_time_val now;
913
914
915 pj_gettimeofday(&now);
918
919 puts("Stream statistics:");
920
921 /* Print duration */
922 PJ_TIME_VAL_SUB(now, stat.start);
923 sprintf(duration, " Duration: %02ld:%02ld:%02ld.%03ld",
924 now.sec / 3600,
925 (now.sec % 3600) / 60,
926 (now.sec % 60),
927 now.msec);
928
929
930 printf(" Info: audio %dHz, %dms/frame, %sB/s (%sB/s +IP hdr)\n",
931 PJMEDIA_PIA_SRATE(&port->info),
932 PJMEDIA_PIA_PTIME(&port->info),
933 good_number(bps, (codec_param->info.avg_bps+7)/8),
934 good_number(ipbps, ((codec_param->info.avg_bps+7)/8) +
935 (40 * 1000 /
936 codec_param->setting.frm_per_pkt /
937 codec_param->info.frm_ptime)));
938
939 if (stat.rx.update_cnt == 0)
940 strcpy(last_update, "never");
941 else {
942 pj_gettimeofday(&now);
943 PJ_TIME_VAL_SUB(now, stat.rx.update);
944 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
945 now.sec / 3600,
946 (now.sec % 3600) / 60,
947 now.sec % 60,
948 now.msec);
949 }
950
951 printf(" RX stat last update: %s\n"
952 " total %s packets %sB received (%sB +IP hdr)%s\n"
953 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n"
954 " (msec) min avg max last dev\n"
955 " loss period: %7.3f %7.3f %7.3f %7.3f %7.3f%s\n"
956 " jitter : %7.3f %7.3f %7.3f %7.3f %7.3f%s\n",
957 last_update,
958 good_number(packets, stat.rx.pkt),
959 good_number(bytes, stat.rx.bytes),
960 good_number(ipbytes, stat.rx.bytes + stat.rx.pkt * 32),
961 "",
962 stat.rx.loss,
963 stat.rx.loss * 100.0 / (stat.rx.pkt + stat.rx.loss),
964 stat.rx.dup,
965 stat.rx.dup * 100.0 / (stat.rx.pkt + stat.rx.loss),
966 stat.rx.reorder,
967 stat.rx.reorder * 100.0 / (stat.rx.pkt + stat.rx.loss),
968 "",
969 stat.rx.loss_period.min / 1000.0,
970 stat.rx.loss_period.mean / 1000.0,
971 stat.rx.loss_period.max / 1000.0,
972 stat.rx.loss_period.last / 1000.0,
973 pj_math_stat_get_stddev(&stat.rx.loss_period) / 1000.0,
974 "",
975 stat.rx.jitter.min / 1000.0,
976 stat.rx.jitter.mean / 1000.0,
977 stat.rx.jitter.max / 1000.0,
978 stat.rx.jitter.last / 1000.0,
979 pj_math_stat_get_stddev(&stat.rx.jitter) / 1000.0,
980 ""
981 );
982
983
984 if (stat.tx.update_cnt == 0)
985 strcpy(last_update, "never");
986 else {
987 pj_gettimeofday(&now);
988 PJ_TIME_VAL_SUB(now, stat.tx.update);
989 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
990 now.sec / 3600,
991 (now.sec % 3600) / 60,
992 now.sec % 60,
993 now.msec);
994 }
995
996 printf(" TX stat last update: %s\n"
997 " total %s packets %sB sent (%sB +IP hdr)%s\n"
998 " pkt loss=%d (%3.1f%%), dup=%d (%3.1f%%), reorder=%d (%3.1f%%)%s\n"
999 " (msec) min avg max last dev\n"
1000 " loss period: %7.3f %7.3f %7.3f %7.3f %7.3f%s\n"
1001 " jitter : %7.3f %7.3f %7.3f %7.3f %7.3f%s\n",
1002 last_update,
1003 good_number(packets, stat.tx.pkt),
1004 good_number(bytes, stat.tx.bytes),
1005 good_number(ipbytes, stat.tx.bytes + stat.tx.pkt * 32),
1006 "",
1007 stat.tx.loss,
1008 stat.tx.loss * 100.0 / (stat.tx.pkt + stat.tx.loss),
1009 stat.tx.dup,
1010 stat.tx.dup * 100.0 / (stat.tx.pkt + stat.tx.loss),
1011 stat.tx.reorder,
1012 stat.tx.reorder * 100.0 / (stat.tx.pkt + stat.tx.loss),
1013 "",
1014 stat.tx.loss_period.min / 1000.0,
1015 stat.tx.loss_period.mean / 1000.0,
1016 stat.tx.loss_period.max / 1000.0,
1017 stat.tx.loss_period.last / 1000.0,
1018 pj_math_stat_get_stddev(&stat.tx.loss_period) / 1000.0,
1019 "",
1020 stat.tx.jitter.min / 1000.0,
1021 stat.tx.jitter.mean / 1000.0,
1022 stat.tx.jitter.max / 1000.0,
1023 stat.tx.jitter.last / 1000.0,
1024 pj_math_stat_get_stddev(&stat.tx.jitter) / 1000.0,
1025 ""
1026 );
1027
1028
1029 printf(" RTT delay : %7.3f %7.3f %7.3f %7.3f %7.3f%s\n",
1030 stat.rtt.min / 1000.0,
1031 stat.rtt.mean / 1000.0,
1032 stat.rtt.max / 1000.0,
1033 stat.rtt.last / 1000.0,
1034 pj_math_stat_get_stddev(&stat.rtt) / 1000.0,
1035 ""
1036 );
1037
1038#if defined(PJMEDIA_HAS_RTCP_XR) && (PJMEDIA_HAS_RTCP_XR != 0)
1039 /* RTCP XR Reports */
1040 do {
1041 char loss[16], dup[16];
1042 char jitter[80];
1043 char toh[80];
1044 char plc[16], jba[16], jbr[16];
1045 char signal_lvl[16], noise_lvl[16], rerl[16];
1046 char r_factor[16], ext_r_factor[16], mos_lq[16], mos_cq[16];
1047 pjmedia_rtcp_xr_stat xr_stat;
1048
1049 if (pjmedia_stream_get_stat_xr(stream, &xr_stat) != PJ_SUCCESS)
1050 break;
1051
1052 puts("\nExtended reports:");
1053
1054 /* Statistics Summary */
1055 puts(" Statistics Summary");
1056
1057 if (xr_stat.rx.stat_sum.l)
1058 sprintf(loss, "%d", xr_stat.rx.stat_sum.lost);
1059 else
1060 sprintf(loss, "(na)");
1061
1062 if (xr_stat.rx.stat_sum.d)
1063 sprintf(dup, "%d", xr_stat.rx.stat_sum.dup);
1064 else
1065 sprintf(dup, "(na)");
1066
1067 if (xr_stat.rx.stat_sum.j) {
1068 unsigned jmin, jmax, jmean, jdev;
1069
1070 SAMPLES_TO_USEC(jmin, xr_stat.rx.stat_sum.jitter.min,
1071 port->info.fmt.det.aud.clock_rate);
1072 SAMPLES_TO_USEC(jmax, xr_stat.rx.stat_sum.jitter.max,
1073 port->info.fmt.det.aud.clock_rate);
1074 SAMPLES_TO_USEC(jmean, xr_stat.rx.stat_sum.jitter.mean,
1075 port->info.fmt.det.aud.clock_rate);
1076 SAMPLES_TO_USEC(jdev,
1077 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.jitter),
1078 port->info.fmt.det.aud.clock_rate);
1079 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",
1080 jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);
1081 } else
1082 sprintf(jitter, "(report not available)");
1083
1084 if (xr_stat.rx.stat_sum.t) {
1085 sprintf(toh, "%11d %11d %11d %11d",
1086 xr_stat.rx.stat_sum.toh.min,
1087 xr_stat.rx.stat_sum.toh.mean,
1088 xr_stat.rx.stat_sum.toh.max,
1089 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh));
1090 } else
1091 sprintf(toh, "(report not available)");
1092
1093 if (xr_stat.rx.stat_sum.update.sec == 0)
1094 strcpy(last_update, "never");
1095 else {
1096 pj_gettimeofday(&now);
1097 PJ_TIME_VAL_SUB(now, xr_stat.rx.stat_sum.update);
1098 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
1099 now.sec / 3600,
1100 (now.sec % 3600) / 60,
1101 now.sec % 60,
1102 now.msec);
1103 }
1104
1105 printf(" RX last update: %s\n"
1106 " begin seq=%d, end seq=%d%s\n"
1107 " pkt loss=%s, dup=%s%s\n"
1108 " (msec) min avg max dev\n"
1109 " jitter : %s\n"
1110 " toh : %s\n",
1111 last_update,
1112 xr_stat.rx.stat_sum.begin_seq, xr_stat.rx.stat_sum.end_seq,
1113 "",
1114 loss, dup,
1115 "",
1116 jitter,
1117 toh
1118 );
1119
1120 if (xr_stat.tx.stat_sum.l)
1121 sprintf(loss, "%d", xr_stat.tx.stat_sum.lost);
1122 else
1123 sprintf(loss, "(na)");
1124
1125 if (xr_stat.tx.stat_sum.d)
1126 sprintf(dup, "%d", xr_stat.tx.stat_sum.dup);
1127 else
1128 sprintf(dup, "(na)");
1129
1130 if (xr_stat.tx.stat_sum.j) {
1131 unsigned jmin, jmax, jmean, jdev;
1132
1133 SAMPLES_TO_USEC(jmin, xr_stat.tx.stat_sum.jitter.min,
1134 port->info.fmt.det.aud.clock_rate);
1135 SAMPLES_TO_USEC(jmax, xr_stat.tx.stat_sum.jitter.max,
1136 port->info.fmt.det.aud.clock_rate);
1137 SAMPLES_TO_USEC(jmean, xr_stat.tx.stat_sum.jitter.mean,
1138 port->info.fmt.det.aud.clock_rate);
1139 SAMPLES_TO_USEC(jdev,
1140 pj_math_stat_get_stddev(&xr_stat.tx.stat_sum.jitter),
1141 port->info.fmt.det.aud.clock_rate);
1142 sprintf(jitter, "%7.3f %7.3f %7.3f %7.3f",
1143 jmin/1000.0, jmean/1000.0, jmax/1000.0, jdev/1000.0);
1144 } else
1145 sprintf(jitter, "(report not available)");
1146
1147 if (xr_stat.tx.stat_sum.t) {
1148 sprintf(toh, "%11d %11d %11d %11d",
1149 xr_stat.tx.stat_sum.toh.min,
1150 xr_stat.tx.stat_sum.toh.mean,
1151 xr_stat.tx.stat_sum.toh.max,
1152 pj_math_stat_get_stddev(&xr_stat.rx.stat_sum.toh));
1153 } else
1154 sprintf(toh, "(report not available)");
1155
1156 if (xr_stat.tx.stat_sum.update.sec == 0)
1157 strcpy(last_update, "never");
1158 else {
1159 pj_gettimeofday(&now);
1160 PJ_TIME_VAL_SUB(now, xr_stat.tx.stat_sum.update);
1161 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
1162 now.sec / 3600,
1163 (now.sec % 3600) / 60,
1164 now.sec % 60,
1165 now.msec);
1166 }
1167
1168 printf(" TX last update: %s\n"
1169 " begin seq=%d, end seq=%d%s\n"
1170 " pkt loss=%s, dup=%s%s\n"
1171 " (msec) min avg max dev\n"
1172 " jitter : %s\n"
1173 " toh : %s\n",
1174 last_update,
1175 xr_stat.tx.stat_sum.begin_seq, xr_stat.tx.stat_sum.end_seq,
1176 "",
1177 loss, dup,
1178 "",
1179 jitter,
1180 toh
1181 );
1182
1183 /* VoIP Metrics */
1184 puts(" VoIP Metrics");
1185
1186 PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.rx.voip_mtc.signal_lvl);
1187 PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.rx.voip_mtc.noise_lvl);
1188 PRINT_VOIP_MTC_VAL(rerl, xr_stat.rx.voip_mtc.rerl);
1189 PRINT_VOIP_MTC_VAL(r_factor, xr_stat.rx.voip_mtc.r_factor);
1190 PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.rx.voip_mtc.ext_r_factor);
1191 PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.rx.voip_mtc.mos_lq);
1192 PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.rx.voip_mtc.mos_cq);
1193
1194 switch ((xr_stat.rx.voip_mtc.rx_config>>6) & 3) {
1195 case PJMEDIA_RTCP_XR_PLC_DIS:
1196 sprintf(plc, "DISABLED");
1197 break;
1198 case PJMEDIA_RTCP_XR_PLC_ENH:
1199 sprintf(plc, "ENHANCED");
1200 break;
1201 case PJMEDIA_RTCP_XR_PLC_STD:
1202 sprintf(plc, "STANDARD");
1203 break;
1204 case PJMEDIA_RTCP_XR_PLC_UNK:
1205 default:
1206 sprintf(plc, "UNKNOWN");
1207 break;
1208 }
1209
1210 switch ((xr_stat.rx.voip_mtc.rx_config>>4) & 3) {
1211 case PJMEDIA_RTCP_XR_JB_FIXED:
1212 sprintf(jba, "FIXED");
1213 break;
1214 case PJMEDIA_RTCP_XR_JB_ADAPTIVE:
1215 sprintf(jba, "ADAPTIVE");
1216 break;
1217 default:
1218 sprintf(jba, "UNKNOWN");
1219 break;
1220 }
1221
1222 sprintf(jbr, "%d", xr_stat.rx.voip_mtc.rx_config & 0x0F);
1223
1224 if (xr_stat.rx.voip_mtc.update.sec == 0)
1225 strcpy(last_update, "never");
1226 else {
1227 pj_gettimeofday(&now);
1228 PJ_TIME_VAL_SUB(now, xr_stat.rx.voip_mtc.update);
1229 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
1230 now.sec / 3600,
1231 (now.sec % 3600) / 60,
1232 now.sec % 60,
1233 now.msec);
1234 }
1235
1236 printf(" RX last update: %s\n"
1237 " packets : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n"
1238 " burst : density=%d (%.2f%%), duration=%d%s\n"
1239 " gap : density=%d (%.2f%%), duration=%d%s\n"
1240 " delay : round trip=%d%s, end system=%d%s\n"
1241 " level : signal=%s%s, noise=%s%s, RERL=%s%s\n"
1242 " quality : R factor=%s, ext R factor=%s\n"
1243 " MOS LQ=%s, MOS CQ=%s\n"
1244 " config : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n"
1245 " JB delay : cur=%d%s, max=%d%s, abs max=%d%s\n",
1246 last_update,
1247 /* pakcets */
1248 xr_stat.rx.voip_mtc.loss_rate, xr_stat.rx.voip_mtc.loss_rate*100.0/256,
1249 xr_stat.rx.voip_mtc.discard_rate, xr_stat.rx.voip_mtc.discard_rate*100.0/256,
1250 /* burst */
1251 xr_stat.rx.voip_mtc.burst_den, xr_stat.rx.voip_mtc.burst_den*100.0/256,
1252 xr_stat.rx.voip_mtc.burst_dur, "ms",
1253 /* gap */
1254 xr_stat.rx.voip_mtc.gap_den, xr_stat.rx.voip_mtc.gap_den*100.0/256,
1255 xr_stat.rx.voip_mtc.gap_dur, "ms",
1256 /* delay */
1257 xr_stat.rx.voip_mtc.rnd_trip_delay, "ms",
1258 xr_stat.rx.voip_mtc.end_sys_delay, "ms",
1259 /* level */
1260 signal_lvl, "dB",
1261 noise_lvl, "dB",
1262 rerl, "",
1263 /* quality */
1264 r_factor, ext_r_factor, mos_lq, mos_cq,
1265 /* config */
1266 plc, jba, jbr, xr_stat.rx.voip_mtc.gmin,
1267 /* JB delay */
1268 xr_stat.rx.voip_mtc.jb_nom, "ms",
1269 xr_stat.rx.voip_mtc.jb_max, "ms",
1270 xr_stat.rx.voip_mtc.jb_abs_max, "ms"
1271 );
1272
1273 PRINT_VOIP_MTC_VAL(signal_lvl, xr_stat.tx.voip_mtc.signal_lvl);
1274 PRINT_VOIP_MTC_VAL(noise_lvl, xr_stat.tx.voip_mtc.noise_lvl);
1275 PRINT_VOIP_MTC_VAL(rerl, xr_stat.tx.voip_mtc.rerl);
1276 PRINT_VOIP_MTC_VAL(r_factor, xr_stat.tx.voip_mtc.r_factor);
1277 PRINT_VOIP_MTC_VAL(ext_r_factor, xr_stat.tx.voip_mtc.ext_r_factor);
1278 PRINT_VOIP_MTC_VAL(mos_lq, xr_stat.tx.voip_mtc.mos_lq);
1279 PRINT_VOIP_MTC_VAL(mos_cq, xr_stat.tx.voip_mtc.mos_cq);
1280
1281 switch ((xr_stat.tx.voip_mtc.rx_config>>6) & 3) {
1282 case PJMEDIA_RTCP_XR_PLC_DIS:
1283 sprintf(plc, "DISABLED");
1284 break;
1285 case PJMEDIA_RTCP_XR_PLC_ENH:
1286 sprintf(plc, "ENHANCED");
1287 break;
1288 case PJMEDIA_RTCP_XR_PLC_STD:
1289 sprintf(plc, "STANDARD");
1290 break;
1291 case PJMEDIA_RTCP_XR_PLC_UNK:
1292 default:
1293 sprintf(plc, "unknown");
1294 break;
1295 }
1296
1297 switch ((xr_stat.tx.voip_mtc.rx_config>>4) & 3) {
1298 case PJMEDIA_RTCP_XR_JB_FIXED:
1299 sprintf(jba, "FIXED");
1300 break;
1301 case PJMEDIA_RTCP_XR_JB_ADAPTIVE:
1302 sprintf(jba, "ADAPTIVE");
1303 break;
1304 default:
1305 sprintf(jba, "unknown");
1306 break;
1307 }
1308
1309 sprintf(jbr, "%d", xr_stat.tx.voip_mtc.rx_config & 0x0F);
1310
1311 if (xr_stat.tx.voip_mtc.update.sec == 0)
1312 strcpy(last_update, "never");
1313 else {
1314 pj_gettimeofday(&now);
1315 PJ_TIME_VAL_SUB(now, xr_stat.tx.voip_mtc.update);
1316 sprintf(last_update, "%02ldh:%02ldm:%02ld.%03lds ago",
1317 now.sec / 3600,
1318 (now.sec % 3600) / 60,
1319 now.sec % 60,
1320 now.msec);
1321 }
1322
1323 printf(" TX last update: %s\n"
1324 " packets : loss rate=%d (%.2f%%), discard rate=%d (%.2f%%)\n"
1325 " burst : density=%d (%.2f%%), duration=%d%s\n"
1326 " gap : density=%d (%.2f%%), duration=%d%s\n"
1327 " delay : round trip=%d%s, end system=%d%s\n"
1328 " level : signal=%s%s, noise=%s%s, RERL=%s%s\n"
1329 " quality : R factor=%s, ext R factor=%s\n"
1330 " MOS LQ=%s, MOS CQ=%s\n"
1331 " config : PLC=%s, JB=%s, JB rate=%s, Gmin=%d\n"
1332 " JB delay : cur=%d%s, max=%d%s, abs max=%d%s\n",
1333 last_update,
1334 /* pakcets */
1335 xr_stat.tx.voip_mtc.loss_rate, xr_stat.tx.voip_mtc.loss_rate*100.0/256,
1336 xr_stat.tx.voip_mtc.discard_rate, xr_stat.tx.voip_mtc.discard_rate*100.0/256,
1337 /* burst */
1338 xr_stat.tx.voip_mtc.burst_den, xr_stat.tx.voip_mtc.burst_den*100.0/256,
1339 xr_stat.tx.voip_mtc.burst_dur, "ms",
1340 /* gap */
1341 xr_stat.tx.voip_mtc.gap_den, xr_stat.tx.voip_mtc.gap_den*100.0/256,
1342 xr_stat.tx.voip_mtc.gap_dur, "ms",
1343 /* delay */
1344 xr_stat.tx.voip_mtc.rnd_trip_delay, "ms",
1345 xr_stat.tx.voip_mtc.end_sys_delay, "ms",
1346 /* level */
1347 signal_lvl, "dB",
1348 noise_lvl, "dB",
1349 rerl, "",
1350 /* quality */
1351 r_factor, ext_r_factor, mos_lq, mos_cq,
1352 /* config */
1353 plc, jba, jbr, xr_stat.tx.voip_mtc.gmin,
1354 /* JB delay */
1355 xr_stat.tx.voip_mtc.jb_nom, "ms",
1356 xr_stat.tx.voip_mtc.jb_max, "ms",
1357 xr_stat.tx.voip_mtc.jb_abs_max, "ms"
1358 );
1359
1360
1361 /* RTT delay (by receiver side) */
1362 printf(" (msec) min avg max last dev\n");
1363 printf(" RTT delay : %7.3f %7.3f %7.3f %7.3f %7.3f%s\n",
1364 xr_stat.rtt.min / 1000.0,
1365 xr_stat.rtt.mean / 1000.0,
1366 xr_stat.rtt.max / 1000.0,
1367 xr_stat.rtt.last / 1000.0,
1368 pj_math_stat_get_stddev(&xr_stat.rtt) / 1000.0,
1369 ""
1370 );
1371 } while (0);
1372#endif /* PJMEDIA_HAS_RTCP_XR */
1373
1374}
1375
pj_status_t pjmedia_codec_register_audio_codecs(pjmedia_endpt *endpt, const pjmedia_audio_codec_config *c)
pj_status_t pjmedia_codec_mgr_get_default_param(pjmedia_codec_mgr *mgr, const pjmedia_codec_info *info, pjmedia_codec_param *param)
pj_status_t pjmedia_codec_mgr_find_codecs_by_id(pjmedia_codec_mgr *mgr, const pj_str_t *codec_id, unsigned *count, const pjmedia_codec_info *p_info[], unsigned prio[])
pj_status_t pjmedia_codec_mgr_get_codec_info(pjmedia_codec_mgr *mgr, unsigned pt, const pjmedia_codec_info **inf)
pj_status_t pjmedia_event_mgr_create(pj_pool_t *pool, unsigned options, pjmedia_event_mgr **mgr)
void pjmedia_event_mgr_destroy(pjmedia_event_mgr *mgr)
pj_status_t pjmedia_wav_player_port_create(pj_pool_t *pool, const char *filename, unsigned ptime, unsigned flags, pj_ssize_t buff_size, pjmedia_port **p_port)
pj_status_t pjmedia_wav_writer_port_create(pj_pool_t *pool, const char *filename, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned flags, pj_ssize_t buff_size, pjmedia_port **p_port)
struct pjmedia_master_port pjmedia_master_port
Definition: master_port.h:65
pj_status_t pjmedia_master_port_create(pj_pool_t *pool, pjmedia_port *u_port, pjmedia_port *d_port, unsigned options, pjmedia_master_port **p_m)
pj_status_t pjmedia_master_port_start(pjmedia_master_port *m)
pj_status_t pjmedia_master_port_destroy(pjmedia_master_port *m, pj_bool_t destroy_ports)
pj_status_t pjmedia_port_destroy(pjmedia_port *port)
unsigned PJMEDIA_PIA_BITS(const pjmedia_port_info *pia)
Definition: port.h:283
unsigned PJMEDIA_PIA_SPF(const pjmedia_port_info *pia)
Definition: port.h:311
unsigned PJMEDIA_PIA_CCNT(const pjmedia_port_info *pia)
Definition: port.h:270
unsigned PJMEDIA_PIA_PTIME(const pjmedia_port_info *pia)
Definition: port.h:297
unsigned PJMEDIA_PIA_SRATE(const pjmedia_port_info *pia)
Definition: port.h:257
pj_status_t pjmedia_transport_srtp_create(pjmedia_endpt *endpt, pjmedia_transport *tp, const pjmedia_srtp_setting *opt, pjmedia_transport **p_tp)
pj_status_t pjmedia_transport_srtp_dtls_start_nego(pjmedia_transport *srtp, const pjmedia_srtp_dtls_nego_param *param)
pj_status_t pjmedia_transport_srtp_start(pjmedia_transport *srtp, const pjmedia_srtp_crypto *tx, const pjmedia_srtp_crypto *rx)
pj_status_t pjmedia_transport_srtp_dtls_get_fingerprint(pjmedia_transport *srtp, const char *hash, char *buf, pj_size_t *len)
pj_status_t pjmedia_transport_udp_create(pjmedia_endpt *endpt, const char *name, int port, unsigned options, pjmedia_transport **p_tp)
pj_status_t pjmedia_transport_udp_attach(pjmedia_endpt *endpt, const char *name, const pjmedia_sock_info *si, unsigned options, pjmedia_transport **p_tp)
@ PJMEDIA_UDP_NO_SRC_ADDR_CHECKING
Definition: transport_udp.h:58
pj_status_t pjmedia_transport_close(pjmedia_transport *tp)
Definition: transport.h:1030
pj_status_t pjmedia_transport_media_start(pjmedia_transport *tp, pj_pool_t *tmp_pool, const pjmedia_sdp_session *sdp_local, const pjmedia_sdp_session *sdp_remote, unsigned media_index)
Definition: transport.h:994
pj_status_t pjmedia_transport_media_stop(pjmedia_transport *tp)
Definition: transport.h:1016
struct pjmedia_endpt pjmedia_endpt
Definition: pjmedia/types.h:186
pjmedia_dir
Definition: pjmedia/types.h:152
@ PJMEDIA_TYPE_AUDIO
Definition: pjmedia/types.h:59
@ PJMEDIA_DIR_ENCODING
Definition: pjmedia/types.h:157
@ PJMEDIA_DIR_ENCODING_DECODING
Definition: pjmedia/types.h:172
@ PJMEDIA_DIR_DECODING
Definition: pjmedia/types.h:163
pj_status_t pjmedia_endpt_create(pj_pool_factory *pf, pj_ioqueue_t *ioqueue, unsigned worker_cnt, pjmedia_endpt **p_endpt)
Definition: endpoint.h:127
pj_status_t pjmedia_endpt_destroy(pjmedia_endpt *endpt)
Definition: endpoint.h:168
pjmedia_codec_mgr * pjmedia_endpt_get_codec_mgr(pjmedia_endpt *endpt)
pj_status_t pjmedia_snd_port_connect(pjmedia_snd_port *snd_port, pjmedia_port *port)
pj_status_t pjmedia_snd_port_create_player(pj_pool_t *pool, int index, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
pj_status_t pjmedia_snd_port_create(pj_pool_t *pool, int rec_id, int play_id, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
pj_status_t pjmedia_snd_port_destroy(pjmedia_snd_port *snd_port)
pj_status_t pjmedia_snd_port_create_rec(pj_pool_t *pool, int index, unsigned clock_rate, unsigned channel_count, unsigned samples_per_frame, unsigned bits_per_sample, unsigned options, pjmedia_snd_port **p_port)
struct pjmedia_snd_port pjmedia_snd_port
Definition: sound_port.h:145
pj_status_t pjmedia_stream_get_stat(const pjmedia_stream *stream, pjmedia_rtcp_stat *stat)
pj_status_t pjmedia_stream_create(pjmedia_endpt *endpt, pj_pool_t *pool, const pjmedia_stream_info *info, pjmedia_transport *tp, void *user_data, pjmedia_stream **p_stream)
pj_status_t pjmedia_stream_start(pjmedia_stream *stream)
pj_status_t pjmedia_stream_destroy(pjmedia_stream *stream)
pj_status_t pjmedia_stream_get_port(pjmedia_stream *stream, pjmedia_port **p_port)
pjmedia_transport * pjmedia_stream_get_transport(pjmedia_stream *st)
pj_status_t pj_init(void)
int pj_bool_t
unsigned short pj_uint16_t
size_t pj_size_t
int pj_status_t
int pj_int32_t
void pj_shutdown(void)
PJ_SUCCESS
PJ_TRUE
PJ_FALSE
void pj_caching_pool_destroy(pj_caching_pool *ch_pool)
void pj_caching_pool_init(pj_caching_pool *ch_pool, const pj_pool_factory_policy *policy, pj_size_t max_capacity)
#define PJ_LOG(level, arg)
pj_pool_factory_policy pj_pool_factory_default_policy
pj_pool_t * pj_pool_create(pj_pool_factory *factory, const char *name, pj_size_t initial_size, pj_size_t increment_size, pj_pool_callback *callback)
void pj_pool_release(pj_pool_t *pool)
void * pj_memcpy(void *dst, const void *src, pj_size_t size)
pj_str_t pj_str(char *str)
pj_str_t * pj_strset(pj_str_t *str, char *ptr, pj_size_t length)
void * pj_memset(void *dst, int c, pj_size_t size)
void pj_bzero(void *dst, pj_size_t size)
int pj_rand(void)
pj_status_t pj_sockaddr_init(int af, pj_sockaddr *addr, const pj_str_t *cp, pj_uint16_t port)
pj_status_t pj_sock_bind(pj_sock_t sockfd, const pj_sockaddr_t *my_addr, int addrlen)
pj_uint16_t pj_sockaddr_get_port(const pj_sockaddr_t *addr)
#define PJ_INET_ADDRSTRLEN
pj_status_t pj_sockaddr_set_port(pj_sockaddr *addr, pj_uint16_t hostport)
#define pj_SOL_IP()
pj_uint32_t pj_htonl(pj_uint32_t hostlong)
pj_uint16_t pj_ntohs(pj_uint16_t netshort)
#define pj_AF_INET()
#define pj_IP_ADD_MEMBERSHIP()
pj_status_t pj_sock_setsockopt(pj_sock_t sockfd, pj_uint16_t level, pj_uint16_t optname, const void *optval, int optlen)
#define pj_SO_REUSEADDR()
#define pj_SOCK_DGRAM()
#define PJ_INVALID_SOCKET
#define pj_SOL_SOCKET()
#define pj_IP_MULTICAST_LOOP()
unsigned pj_sockaddr_get_len(const pj_sockaddr_t *addr)
pj_status_t pj_sockaddr_in_init(pj_sockaddr_in *addr, const pj_str_t *cp, pj_uint16_t port)
void pj_sockaddr_cp(pj_sockaddr_t *dst, const pj_sockaddr_t *src)
pj_status_t pj_sock_socket(int family, int type, int protocol, pj_sock_t *sock)
char * pj_inet_ntop2(int af, const void *src, char *dst, int size)
pj_status_t pj_gettimeofday(pj_time_val *tv)
#define PJ_TIME_VAL_SUB(t1, t2)
#define pj_assert(expr)
#define PJ_ASSERT_RETURN(expr, retval)
unsigned pj_hex_digit_to_val(unsigned char c)
int pj_isxdigit(unsigned char c)
unsigned pj_math_stat_get_stddev(const pj_math_stat *stat)
Include all codecs API in PJMEDIA-CODEC.
PJMEDIA main header file.
pj_uint16_t sa_family
pj_pool_factory factory
pj_uint16_t sin_port
pj_in_addr sin_addr
pj_ssize_t slen
unsigned clock_rate
Definition: format.h:259
Definition: codec.h:235
unsigned pt
Definition: codec.h:237
Definition: codec.h:705
Definition: codec.h:268
struct pjmedia_codec_param::@8 info
pj_uint32_t avg_bps
Definition: codec.h:276
pj_uint8_t frm_per_pkt
Definition: codec.h:299
struct pjmedia_codec_param::@9 setting
pj_uint16_t frm_ptime
Definition: codec.h:279
union pjmedia_format::@11 det
pjmedia_audio_format_detail aud
Definition: format.h:323
pjmedia_format fmt
Definition: port.h:247
Definition: port.h:378
pjmedia_port_info info
Definition: port.h:379
Definition: rtcp.h:206
pj_math_stat rtt
Definition: rtcp.h:212
pj_time_val start
Definition: rtcp.h:207
pjmedia_rtcp_stream_stat rx
Definition: rtcp.h:210
pjmedia_rtcp_stream_stat tx
Definition: rtcp.h:209
pj_time_val update
Definition: rtcp.h:181
pj_math_stat loss_period
Definition: rtcp.h:190
unsigned reorder
Definition: rtcp.h:187
unsigned dup
Definition: rtcp.h:188
pj_math_stat jitter
Definition: rtcp.h:197
unsigned loss
Definition: rtcp.h:186
unsigned update_cnt
Definition: rtcp.h:182
pj_uint32_t pkt
Definition: rtcp.h:183
pj_uint32_t bytes
Definition: rtcp.h:184
Definition: rtcp_xr.h:303
pjmedia_rtcp_xr_stream_stat tx
Definition: rtcp_xr.h:305
pj_math_stat rtt
Definition: rtcp_xr.h:306
pjmedia_rtcp_xr_stream_stat rx
Definition: rtcp_xr.h:304
unsigned j
Definition: rtcp_xr.h:258
pj_uint8_t gmin
Definition: rtcp_xr.h:282
pj_uint8_t r_factor
Definition: rtcp_xr.h:283
pj_time_val update
Definition: rtcp_xr.h:247
pj_int8_t signal_lvl
Definition: rtcp_xr.h:279
pj_uint16_t jb_max
Definition: rtcp_xr.h:294
pj_uint8_t rerl
Definition: rtcp_xr.h:281
pj_uint16_t jb_abs_max
Definition: rtcp_xr.h:296
pj_uint16_t gap_dur
Definition: rtcp_xr.h:276
pj_math_stat jitter
Definition: rtcp_xr.h:264
pj_uint32_t begin_seq
Definition: rtcp_xr.h:249
pj_uint16_t jb_nom
Definition: rtcp_xr.h:292
pj_uint32_t end_seq
Definition: rtcp_xr.h:250
pj_uint16_t rnd_trip_delay
Definition: rtcp_xr.h:277
pj_uint16_t burst_dur
Definition: rtcp_xr.h:275
unsigned t
Definition: rtcp_xr.h:259
pj_int8_t noise_lvl
Definition: rtcp_xr.h:280
pj_uint8_t ext_r_factor
Definition: rtcp_xr.h:285
pj_math_stat toh
Definition: rtcp_xr.h:265
unsigned l
Definition: rtcp_xr.h:256
pj_uint8_t loss_rate
Definition: rtcp_xr.h:271
pj_uint8_t mos_lq
Definition: rtcp_xr.h:287
unsigned d
Definition: rtcp_xr.h:257
pj_uint8_t mos_cq
Definition: rtcp_xr.h:289
pj_uint8_t gap_den
Definition: rtcp_xr.h:274
unsigned dup
Definition: rtcp_xr.h:263
pj_uint16_t end_sys_delay
Definition: rtcp_xr.h:278
pj_uint8_t burst_den
Definition: rtcp_xr.h:273
pj_uint8_t discard_rate
Definition: rtcp_xr.h:272
pj_uint8_t rx_config
Definition: rtcp_xr.h:291
unsigned lost
Definition: rtcp_xr.h:262
Definition: transport.h:276
pj_sock_t rtp_sock
Definition: transport.h:278
pj_sock_t rtcp_sock
Definition: transport.h:288
pj_sockaddr rtp_addr_name
Definition: transport.h:285
pj_sockaddr rtcp_addr_name
Definition: transport.h:295
Definition: transport_srtp.h:91
pj_str_t key
Definition: transport_srtp.h:93
pj_str_t name
Definition: transport_srtp.h:96
Definition: transport_srtp.h:333
pj_sockaddr rem_addr
Definition: transport_srtp.h:344
pj_sockaddr rem_rtcp
Definition: transport_srtp.h:349
pj_bool_t is_role_active
Definition: transport_srtp.h:356
Definition: stream.h:93
unsigned rx_pt
Definition: stream.h:118
pjmedia_dir dir
Definition: stream.h:96
pjmedia_type type
Definition: stream.h:94
pj_sockaddr rem_addr
Definition: stream.h:98
unsigned tx_pt
Definition: stream.h:117
pj_uint32_t ssrc
Definition: stream.h:122
pjmedia_codec_info fmt
Definition: stream.h:115
pj_sockaddr rem_rtcp
Definition: stream.h:99
Definition: transport.h:504
Definition: jbsim.c:73
Secure RTP (SRTP) transport.
pj_addr_hdr addr
pj_sockaddr_in ipv4

 


PJMEDIA small footprint Open Source media stack
Copyright (C) 2006-2008 Teluu Inc.