📄 siprtp.c
字号:
/* Bytes */
MIN_(min_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
MAX_(max_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
AVG_(avg_stat.rx.bytes, audio->rtcp.stat.rx.bytes);
/* Packet loss */
MIN_(min_stat.rx.loss, audio->rtcp.stat.rx.loss);
MAX_(max_stat.rx.loss, audio->rtcp.stat.rx.loss);
AVG_(avg_stat.rx.loss, audio->rtcp.stat.rx.loss);
/* Packet dup */
MIN_(min_stat.rx.dup, audio->rtcp.stat.rx.dup);
MAX_(max_stat.rx.dup, audio->rtcp.stat.rx.dup);
AVG_(avg_stat.rx.dup, audio->rtcp.stat.rx.dup);
/* Packet reorder */
MIN_(min_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
MAX_(max_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
AVG_(avg_stat.rx.reorder, audio->rtcp.stat.rx.reorder);
/* Jitter */
MIN_(min_stat.rx.jitter.min, audio->rtcp.stat.rx.jitter.min);
MAX_(max_stat.rx.jitter.max, audio->rtcp.stat.rx.jitter.max);
AVG_(avg_stat.rx.jitter.avg, audio->rtcp.stat.rx.jitter.avg);
/* TX Statistisc: */
/* Packets */
MIN_(min_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
MAX_(max_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
AVG_(avg_stat.tx.pkt, audio->rtcp.stat.tx.pkt);
/* Bytes */
MIN_(min_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
MAX_(max_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
AVG_(avg_stat.tx.bytes, audio->rtcp.stat.tx.bytes);
/* Packet loss */
MIN_(min_stat.tx.loss, audio->rtcp.stat.tx.loss);
MAX_(max_stat.tx.loss, audio->rtcp.stat.tx.loss);
AVG_(avg_stat.tx.loss, audio->rtcp.stat.tx.loss);
/* Packet dup */
MIN_(min_stat.tx.dup, audio->rtcp.stat.tx.dup);
MAX_(max_stat.tx.dup, audio->rtcp.stat.tx.dup);
AVG_(avg_stat.tx.dup, audio->rtcp.stat.tx.dup);
/* Packet reorder */
MIN_(min_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
MAX_(max_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
AVG_(avg_stat.tx.reorder, audio->rtcp.stat.tx.reorder);
/* Jitter */
MIN_(min_stat.tx.jitter.min, audio->rtcp.stat.tx.jitter.min);
MAX_(max_stat.tx.jitter.max, audio->rtcp.stat.tx.jitter.max);
AVG_(avg_stat.tx.jitter.avg, audio->rtcp.stat.tx.jitter.avg);
/* RTT */
MIN_(min_stat.rtt.min, audio->rtcp.stat.rtt.min);
MAX_(max_stat.rtt.max, audio->rtcp.stat.rtt.max);
AVG_(avg_stat.rtt.avg, audio->rtcp.stat.rtt.avg);
++count;
}
if (count == 0) {
puts("No active calls");
return;
}
printf("Total %d call(s) active.\n"
" Average Statistics\n"
" min avg max \n"
" -----------------------\n"
" call duration: %7d %7d %7d %s\n"
" connect delay: %7d %7d %7d %s\n"
" RX stat:\n"
" packets: %7s %7s %7s %s\n"
" payload: %7s %7s %7s %s\n"
" loss: %7d %7d %7d %s\n"
" percent loss: %7.3f %7.3f %7.3f %s\n"
" dup: %7d %7d %7d %s\n"
" reorder: %7d %7d %7d %s\n"
" jitter: %7.3f %7.3f %7.3f %s\n"
" TX stat:\n"
" packets: %7s %7s %7s %s\n"
" payload: %7s %7s %7s %s\n"
" loss: %7d %7d %7d %s\n"
" percent loss: %7.3f %7.3f %7.3f %s\n"
" dup: %7d %7d %7d %s\n"
" reorder: %7d %7d %7d %s\n"
" jitter: %7.3f %7.3f %7.3f %s\n"
" RTT : %7.3f %7.3f %7.3f %s\n"
,
count,
call_dur.min/1000, call_dur.avg/1000, call_dur.max/1000,
"seconds",
call_pdd.min, call_pdd.avg, call_pdd.max,
"ms",
/* rx */
good_number(srx_min, min_stat.rx.pkt),
good_number(srx_avg, avg_stat.rx.pkt),
good_number(srx_max, max_stat.rx.pkt),
"packets",
good_number(brx_min, min_stat.rx.bytes),
good_number(brx_avg, avg_stat.rx.bytes),
good_number(brx_max, max_stat.rx.bytes),
"bytes",
min_stat.rx.loss, avg_stat.rx.loss, max_stat.rx.loss,
"packets",
min_stat.rx.loss*100.0/(min_stat.rx.pkt+min_stat.rx.loss),
avg_stat.rx.loss*100.0/(avg_stat.rx.pkt+avg_stat.rx.loss),
max_stat.rx.loss*100.0/(max_stat.rx.pkt+max_stat.rx.loss),
"%",
min_stat.rx.dup, avg_stat.rx.dup, max_stat.rx.dup,
"packets",
min_stat.rx.reorder, avg_stat.rx.reorder, max_stat.rx.reorder,
"packets",
min_stat.rx.jitter.min/1000.0,
avg_stat.rx.jitter.avg/1000.0,
max_stat.rx.jitter.max/1000.0,
"ms",
/* tx */
good_number(stx_min, min_stat.tx.pkt),
good_number(stx_avg, avg_stat.tx.pkt),
good_number(stx_max, max_stat.tx.pkt),
"packets",
good_number(btx_min, min_stat.tx.bytes),
good_number(btx_avg, avg_stat.tx.bytes),
good_number(btx_max, max_stat.tx.bytes),
"bytes",
min_stat.tx.loss, avg_stat.tx.loss, max_stat.tx.loss,
"packets",
min_stat.tx.loss*100.0/(min_stat.tx.pkt+min_stat.tx.loss),
avg_stat.tx.loss*100.0/(avg_stat.tx.pkt+avg_stat.tx.loss),
max_stat.tx.loss*100.0/(max_stat.tx.pkt+max_stat.tx.loss),
"%",
min_stat.tx.dup, avg_stat.tx.dup, max_stat.tx.dup,
"packets",
min_stat.tx.reorder, avg_stat.tx.reorder, max_stat.tx.reorder,
"packets",
min_stat.tx.jitter.min/1000.0,
avg_stat.tx.jitter.avg/1000.0,
max_stat.tx.jitter.max/1000.0,
"ms",
/* rtt */
min_stat.rtt.min/1000.0,
avg_stat.rtt.avg/1000.0,
max_stat.rtt.max/1000.0,
"ms"
);
}
#include "siprtp_report.c"
static void list_calls()
{
unsigned i;
puts("List all calls:");
for (i=0; i<app.max_calls; ++i) {
if (!app.call[i].inv)
continue;
print_call(i);
}
}
static void hangup_call(unsigned index)
{
pjsip_tx_data *tdata;
pj_status_t status;
if (app.call[index].inv == NULL)
return;
status = pjsip_inv_end_session(app.call[index].inv, 603, NULL, &tdata);
if (status==PJ_SUCCESS && tdata!=NULL)
pjsip_inv_send_msg(app.call[index].inv, tdata);
}
static void hangup_all_calls()
{
unsigned i;
for (i=0; i<app.max_calls; ++i) {
if (!app.call[i].inv)
continue;
hangup_call(i);
}
/* Wait until all calls are terminated */
for (i=0; i<app.max_calls; ++i) {
while (app.call[i].inv)
pj_thread_sleep(10);
}
}
static pj_bool_t simple_input(const char *title, char *buf, pj_size_t len)
{
char *p;
printf("%s (empty to cancel): ", title); fflush(stdout);
fgets(buf, len, stdin);
/* Remove trailing newlines. */
for (p=buf; ; ++p) {
if (*p=='\r' || *p=='\n') *p='\0';
else if (!*p) break;
}
if (!*buf)
return PJ_FALSE;
return PJ_TRUE;
}
static const char *MENU =
"\n"
"Enter menu character:\n"
" s Summary\n"
" l List all calls\n"
" h Hangup a call\n"
" H Hangup all calls\n"
" q Quit\n"
"\n";
/* Main screen menu */
static void console_main()
{
char input1[10];
unsigned i;
printf("%s", MENU);
for (;;) {
printf(">>> "); fflush(stdout);
fgets(input1, sizeof(input1), stdin);
switch (input1[0]) {
case 's':
print_avg_stat();
break;
case 'l':
list_calls();
break;
case 'h':
if (!simple_input("Call number to hangup", input1, sizeof(input1)))
break;
i = atoi(input1);
hangup_call(i);
break;
case 'H':
hangup_all_calls();
break;
case 'q':
goto on_exit;
default:
puts("Invalid command");
printf("%s", MENU);
break;
}
fflush(stdout);
}
on_exit:
hangup_all_calls();
}
/*****************************************************************************
* Below is a simple module to log all incoming and outgoing SIP messages
*/
/* Notification on incoming messages */
static pj_bool_t logger_on_rx_msg(pjsip_rx_data *rdata)
{
PJ_LOG(4,(THIS_FILE, "RX %d bytes %s from %s:%d:\n"
"%s\n"
"--end msg--",
rdata->msg_info.len,
pjsip_rx_data_get_info(rdata),
rdata->pkt_info.src_name,
rdata->pkt_info.src_port,
rdata->msg_info.msg_buf));
/* Always return false, otherwise messages will not get processed! */
return PJ_FALSE;
}
/* Notification on outgoing messages */
static pj_status_t logger_on_tx_msg(pjsip_tx_data *tdata)
{
/* Important note:
* tp_info field is only valid after outgoing messages has passed
* transport layer. So don't try to access tp_info when the module
* has lower priority than transport layer.
*/
PJ_LOG(4,(THIS_FILE, "TX %d bytes %s to %s:%d:\n"
"%s\n"
"--end msg--",
(tdata->buf.cur - tdata->buf.start),
pjsip_tx_data_get_info(tdata),
tdata->tp_info.dst_name,
tdata->tp_info.dst_port,
tdata->buf.start));
/* Always return success, otherwise message will not get sent! */
return PJ_SUCCESS;
}
/* The module instance. */
static pjsip_module msg_logger =
{
NULL, NULL, /* prev, next. */
{ "mod-siprtp-log", 14 }, /* Name. */
-1, /* Id */
PJSIP_MOD_PRIORITY_TRANSPORT_LAYER-1,/* Priority */
NULL, /* load() */
NULL, /* start() */
NULL, /* stop() */
NULL, /* unload() */
&logger_on_rx_msg, /* on_rx_request() */
&logger_on_rx_msg, /* on_rx_response() */
&logger_on_tx_msg, /* on_tx_request. */
&logger_on_tx_msg, /* on_tx_response() */
NULL, /* on_tsx_state() */
};
/*****************************************************************************
* Console application custom logging:
*/
static FILE *log_file;
static void app_log_writer(int level, const char *buffer, int len)
{
/* Write to both stdout and file. */
if (level <= app.app_log_level)
pj_log_write(level, buffer, len);
if (log_file) {
fwrite(buffer, len, 1, log_file);
fflush(log_file);
}
}
pj_status_t app_logging_init(void)
{
/* Redirect log function to ours */
pj_log_set_log_func( &app_log_writer );
/* If output log file is desired, create the file: */
if (app.log_filename) {
log_file = fopen(app.log_filename, "wt");
if (log_file == NULL) {
PJ_LOG(1,(THIS_FILE, "Unable to open log file %s",
app.log_filename));
return -1;
}
}
return PJ_SUCCESS;
}
void app_logging_shutdown(void)
{
/* Close logging file, if any: */
if (log_file) {
fclose(log_file);
log_file = NULL;
}
}
/*
* main()
*/
int main(int argc, char *argv[])
{
unsigned i;
pj_status_t status;
/* Must init PJLIB first */
status = pj_init();
if (status != PJ_SUCCESS)
return 1;
/* Get command line options */
status = init_options(argc, argv);
if (status != PJ_SUCCESS)
return 1;
/* Verify options: */
/* Auto-quit can not be specified for UAS */
if (app.auto_quit && app.uri_to_call.slen == 0) {
printf("Error: --auto-quit option only valid for outgoing "
"mode (UAC) only\n");
return 1;
}
/* Init logging */
status = app_logging_init();
if (status != PJ_SUCCESS)
return 1;
/* Init SIP etc */
status = init_sip();
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Initialization has failed", status);
destroy_sip();
return 1;
}
/* Register module to log incoming/outgoing messages */
pjsip_endpt_register_module(app.sip_endpt, &msg_logger);
/* Init media */
status = init_media();
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Media initialization failed", status);
destroy_sip();
return 1;
}
/* Start worker threads */
for (i=0; i<app.thread_count; ++i) {
pj_thread_create( app.pool, "app", &sip_worker_thread, NULL,
0, 0, &app.sip_thread[i]);
}
/* If URL is specified, then make call immediately */
if (app.uri_to_call.slen) {
unsigned i;
PJ_LOG(3,(THIS_FILE, "Making %d calls to %s..", app.max_calls,
app.uri_to_call.ptr));
for (i=0; i<app.max_calls; ++i) {
status = make_call(&app.uri_to_call);
if (status != PJ_SUCCESS) {
app_perror(THIS_FILE, "Error making call", status);
break;
}
}
if (app.auto_quit) {
/* Wait for calls to complete */
while (app.uac_calls < app.max_calls)
pj_thread_sleep(100);
pj_thread_sleep(200);
} else {
/* Start user interface loop */
console_main();
}
} else {
PJ_LOG(3,(THIS_FILE, "Ready for incoming calls (max=%d)",
app.max_calls));
/* Start user interface loop */
console_main();
}
/* Shutting down... */
destroy_sip();
destroy_media();
if (app.pool) {
pj_pool_release(app.pool);
app.pool = NULL;
pj_caching_pool_destroy(&app.cp);
}
app_logging_shutdown();
/* Shutdown PJLIB */
pj_shutdown();
return 0;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -