[asterisk-commits] oej: trunk r128197 - in /trunk: channels/ include/asterisk/ main/

SVN commits to the Asterisk project asterisk-commits at lists.digium.com
Sat Jul 5 14:27:43 CDT 2008


Author: oej
Date: Sat Jul  5 14:27:42 2008
New Revision: 128197

URL: http://svn.digium.com/view/asterisk?view=rev&rev=128197
Log:
Add new SIP cli command "sip show channelstats" that displays some QoS data (if we have RTCP reports
and not use the p2p rtp bridge). I could not find a way to detect us using the p2p bridge, which
would be nice.


Modified:
    trunk/channels/chan_sip.c
    trunk/include/asterisk/rtp.h
    trunk/main/rtp.c

Modified: trunk/channels/chan_sip.c
URL: http://svn.digium.com/view/asterisk/trunk/channels/chan_sip.c?view=diff&rev=128197&r1=128196&r2=128197
==============================================================================
--- trunk/channels/chan_sip.c (original)
+++ trunk/channels/chan_sip.c Sat Jul  5 14:27:42 2008
@@ -311,6 +311,22 @@
 	INV_CANCELLED = 7,	/*!< Transaction cancelled by client or server in non-terminated state */
 };
 
+/*! \brief Readable descriptions of device states.
+       \note Should be aligned to above table as index */
+static const struct invstate2stringtable {
+	const enum invitestates state;
+	const char const *desc;
+} invitestate2string[] = {
+	{INV_NONE,              "None"  },
+	{INV_CALLING,           "Calling (Trying)"},
+	{INV_PROCEEDING,        "Proceeding "},
+	{INV_EARLY_MEDIA,       "Early media"},
+	{INV_COMPLETED,         "Completed (done)"},
+	{INV_CONFIRMED,         "Confirmed (up)"},
+	{INV_TERMINATED,        "Done"},
+	{INV_CANCELLED,         "Cancelled"}
+};
+
 enum xmittype {
 	XMIT_CRITICAL = 2,              /*!< Transmit critical SIP message reliably, with re-transmits.
                                               If it fails, it's critical and will cause a teardown of the session */
@@ -452,6 +468,14 @@
 	int force;                      /*!< If it's an outbound proxy, Force use of this outbound proxy for all outbound requests */
 	/* Room for a SRV record chain based on the name */
 };
+
+/*! \brief argument for the 'show channels|subscriptions' callback. */
+struct __show_chan_arg { 
+	int fd;
+	int subscriptions;
+	int numchans;   /* return value */
+};
+
 
 /*! \brief States whether a SIP message can create a dialog in Asterisk. */
 enum can_create_dialog {
@@ -2018,6 +2042,7 @@
 static char *complete_sip_show_user(const char *line, const char *word, int pos, int state);
 static char *complete_sipnotify(const char *line, const char *word, int pos, int state);
 static char *sip_show_channel(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
+static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *sip_show_history(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a);
 static char *sip_do_debug_ip(int fd, char *arg);
 static char *sip_do_debug_peer(int fd, char *arg);
@@ -14117,6 +14142,91 @@
 	return CLI_SUCCESS;
 }
 
+/*! \brief Callback for show_chanstats */
+static int show_chanstats_cb(void *__cur, void *__arg, int flags)
+{
+#define FORMAT2 "%-15.15s  %-11.11s  %-8.8s %-10.10s  %-10.10s (%-2.2s) %-6.6s %-10.10s  %-10.10s ( %%) %-6.6s\n"
+#define FORMAT  "%-15.15s  %-11.11s  %-8.8s %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u %-10.10u%-1.1s %-10.10u (%-2.2u%%) %-6.6u\n"
+	struct sip_pvt *cur = __cur;
+	unsigned int rxcount;
+	unsigned int txcount;
+	char durbuf[10];
+        int duration;
+        int durh, durm, durs;
+	struct ast_channel *c = cur->owner;
+	struct __show_chan_arg *arg = __arg;
+	int fd = arg->fd;
+
+
+	if (cur->subscribed != NONE) /* Subscriptions */
+		return 0;	/* don't care, we scan all channels */
+
+	if (!cur->rtp) {
+		if (sipdebug)
+			ast_cli(fd, "%-15.15s  %-11.11s (inv state: %s) -- %s\n", ast_inet_ntoa(cur->sa.sin_addr), cur->callid, invitestate2string[cur->invitestate].desc, "-- No RTP active");
+		return 0;	/* don't care, we scan all channels */
+	}
+	rxcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXCOUNT);
+	txcount = ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXCOUNT);
+
+	/* Find the duration of this channel */
+	if (c && c->cdr && !ast_tvzero(c->cdr->start)) {
+		duration = (int)(ast_tvdiff_ms(ast_tvnow(), c->cdr->start) / 1000);
+		durh = duration / 3600;
+		durm = (duration % 3600) / 60;
+		durs = duration % 60;
+		snprintf(durbuf, sizeof(durbuf), "%02d:%02d:%02d", durh, durm, durs);
+	} else {
+		durbuf[0] = '\0';
+	}
+	/* Print stats for every call with RTP */
+	ast_cli(fd, FORMAT, 
+		ast_inet_ntoa(cur->sa.sin_addr), 
+		cur->callid, 
+		durbuf,
+		rxcount > (unsigned int) 100000 ? (unsigned int) (rxcount)/(unsigned int) 1000 : rxcount,
+		rxcount > (unsigned int) 100000 ? "K":" ",
+		ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS),
+		rxcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXPLOSS) / rxcount * 100) : 0,
+		ast_rtp_get_qosvalue(cur->rtp, AST_RTP_RXJITTER),
+		txcount > (unsigned int) 100000 ? (unsigned int) (txcount)/(unsigned int) 1000 : txcount,
+		txcount > (unsigned int) 100000 ? "K":" ",
+		ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS),
+		txcount > ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS) ? (unsigned int) (ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXPLOSS)/ txcount * 100) : 0,
+		ast_rtp_get_qosvalue(cur->rtp, AST_RTP_TXJITTER)
+	);
+	arg->numchans++;
+
+	return 0;	/* don't care, we scan all channels */
+}
+
+/*! \brief SIP show channelstats CLI (main function) */
+static char *sip_show_channelstats(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
+{
+	struct __show_chan_arg arg = { .fd = a->fd, .numchans = 0 };
+
+	switch (cmd) {
+	case CLI_INIT:
+		e->command = "sip show channelstats";
+		e->usage =
+			"Usage: sip show channelstats\n"
+			"       Lists all currently active SIP channel's RTCP statistics.\n"
+			"       Note that calls in the much optimized RTP P2P bridge mode will not show any packets here.";
+		return NULL;
+	}
+
+	if (a->argc != 3)
+		return CLI_SHOWUSAGE;
+
+	ast_cli(a->fd, FORMAT2, "Peer", "Call ID", "Duration", "Recv: Pack", "Lost", "%", "Jitter", "Send: Pack", "Lost", "Jitter");
+	/* iterate on the container and invoke the callback on each item */
+	ao2_t_callback(dialogs, OBJ_NODATA, show_chanstats_cb, &arg, "callback to sip show chanstats");
+	ast_cli(a->fd, "%d active SIP channel%s\n", arg.numchans, (arg.numchans != 1) ? "s" : ""); 
+	return CLI_SUCCESS;
+}
+#undef FORMAT
+#undef FORMAT2
+
 /*! \brief List global settings for the SIP channel */
 static char *sip_show_settings(struct ast_cli_entry *e, int cmd, struct ast_cli_args *a)
 {
@@ -14334,13 +14444,6 @@
  * that support iteration through callbacks will be a lot easier.
  */
 
-/*! \brief argument for the 'show channels|subscriptions' callback. */
-struct __show_chan_arg { 
-	int fd;
-	int subscriptions;
-	int numchans;   /* return value */
-};
-
 #define FORMAT4 "%-15.15s  %-10.10s  %-15.15s  %-15.15s  %-13.13s  %-15.15s %-10.10s %-6.6d\n"
 #define FORMAT3 "%-15.15s  %-10.10s  %-15.15s  %-15.15s  %-13.13s  %-15.15s %-10.10s %-6.6s\n"
 #define FORMAT2 "%-15.15s  %-10.10s  %-15.15s  %-15.15s  %-7.7s  %-15.15s %-6.6s\n"
@@ -14436,8 +14539,6 @@
  * given position. As many functions of this kind, each invokation has
  * O(state) time complexity so be careful in using it.
  */
-
-
 static char *complete_sipch(const char *line, const char *word, int pos, int state)
 {
 	int which=0;
@@ -23001,12 +23102,13 @@
 static struct ast_cli_entry cli_sip_do_history_deprecated = AST_CLI_DEFINE(sip_do_history_deprecated, "Enable/Disable SIP history");
 /*! \brief SIP Cli commands definition */
 static struct ast_cli_entry cli_sip[] = {
-	AST_CLI_DEFINE(sip_show_channels, "List active SIP channels/subscriptions"),
+	AST_CLI_DEFINE(sip_show_channels, "List active SIP channels or subscriptions"),
+	AST_CLI_DEFINE(sip_show_channelstats, "List statistics for active SIP channels"),
 	AST_CLI_DEFINE(sip_show_domains, "List our local SIP domains."),
 	AST_CLI_DEFINE(sip_show_inuse, "List all inuse/limits"),
 	AST_CLI_DEFINE(sip_show_objects, "List all SIP object allocations"),
 	AST_CLI_DEFINE(sip_show_peers, "List defined SIP peers"),
-	AST_CLI_DEFINE(sip_dbdump, "dump peer info into realtime db sql format"),
+	AST_CLI_DEFINE(sip_dbdump, "Dump peer info into realtime database SQL format"),
 	AST_CLI_DEFINE(sip_show_registry, "List SIP registration status"),
 	AST_CLI_DEFINE(sip_unregister, "Unregister (force expiration) a SIP peer from the registery\n"),
 	AST_CLI_DEFINE(sip_show_settings, "Show SIP global settings"),

Modified: trunk/include/asterisk/rtp.h
URL: http://svn.digium.com/view/asterisk/trunk/include/asterisk/rtp.h?view=diff&rev=128197&r1=128196&r2=128197
==============================================================================
--- trunk/include/asterisk/rtp.h (original)
+++ trunk/include/asterisk/rtp.h Sat Jul  5 14:27:42 2008
@@ -67,6 +67,17 @@
 	AST_RTP_TRY_PARTIAL,
 	/*! RTP structure exists and native bridge can occur */
 	AST_RTP_TRY_NATIVE,
+};
+
+/*! \brief Variables used in ast_rtcp_get function */
+enum ast_rtp_qos_vars {
+	AST_RTP_TXCOUNT,
+	AST_RTP_RXCOUNT,
+	AST_RTP_TXJITTER,
+	AST_RTP_RXJITTER,
+	AST_RTP_RXPLOSS,
+	AST_RTP_TXPLOSS,
+	AST_RTP_RTT
 };
 
 struct ast_rtp;
@@ -268,6 +279,10 @@
 
 /*! \brief Get QOS stats on a RTP channel */
 int ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, char *buf, unsigned int buflen);
+
+/*! \brief Return RTP and RTCP QoS values */
+unsigned int ast_rtp_get_qosvalue(struct ast_rtp *rtp, enum ast_rtp_qos_vars value);
+
 /*! \brief Set RTPAUDIOQOS(...) variables on a channel when it is being hung up */
 void ast_rtp_set_vars(struct ast_channel *chan, struct ast_rtp *rtp);
 

Modified: trunk/main/rtp.c
URL: http://svn.digium.com/view/asterisk/trunk/main/rtp.c?view=diff&rev=128197&r1=128196&r2=128197
==============================================================================
--- trunk/main/rtp.c (original)
+++ trunk/main/rtp.c Sat Jul  5 14:27:42 2008
@@ -2626,6 +2626,37 @@
 	rtp->rxseqno = 0;
 }
 
+/*! Get QoS values from RTP and RTCP data (used in "sip show channelstats") */
+unsigned int ast_rtp_get_qosvalue(struct ast_rtp *rtp, enum ast_rtp_qos_vars value)
+{
+	if (rtp == NULL) {
+		if (option_debug > 1)
+			ast_log(LOG_DEBUG, "NO RTP Structure? Kidding me? \n");
+		return 0;
+	}
+	if (option_debug > 1 && rtp->rtcp == NULL) {
+		ast_log(LOG_DEBUG, "NO RTCP structure. Maybe in RTP p2p bridging mode? \n");
+	}
+
+	switch (value) {
+	case AST_RTP_TXCOUNT:
+		return (unsigned int) rtp->txcount;
+	case AST_RTP_RXCOUNT:
+		return (unsigned int) rtp->rxcount;
+	case AST_RTP_TXJITTER:
+		return (unsigned int) (rtp->rxjitter * 100.0);
+	case AST_RTP_RXJITTER:
+		return (unsigned int) rtp->rtcp ? (rtp->rtcp->reported_jitter / (unsigned int) 65536.0) : 0;
+	case AST_RTP_RXPLOSS:
+		return rtp->rtcp ? (rtp->rtcp->expected_prior - rtp->rtcp->received_prior) : 0;
+	case AST_RTP_TXPLOSS:
+		return rtp->rtcp ? rtp->rtcp->reported_lost : 0;
+	case AST_RTP_RTT:
+		return (unsigned int) rtp->rtcp ? rtp->rtcp->rtt * 100 : 0;
+	}
+	return 0;	/* To make the compiler happy */
+}
+
 static double __ast_rtp_get_qos(struct ast_rtp *rtp, const char *qos, int *found)
 {
 	*found = 1;




More information about the asterisk-commits mailing list