Add support for receiver reports (bug #3236, with mods)
authorMark Spencer <markster@digium.com>
Sat, 12 Feb 2005 18:52:14 +0000 (18:52 +0000)
committerMark Spencer <markster@digium.com>
Sat, 12 Feb 2005 18:52:14 +0000 (18:52 +0000)
git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@5012 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_iax2.c
channels/iax2-parser.c
channels/iax2-parser.h
channels/iax2.h

index b5d44ae..029294f 100755 (executable)
@@ -360,6 +360,16 @@ static int max_jitter_buffer = MAX_JITTER_BUFFER;
 /* If we have less than this much excess real jitter buffer, enlarge it. */
 static int min_jitter_buffer = MIN_JITTER_BUFFER;
 
+struct iax_rr {
+       int jitter;
+       int losspct;
+       int losscnt;
+       int packets;
+       int delay;
+       int dropped;
+       int ooo;
+};
+
 struct chan_iax2_pvt {
        /* Socket to send/receive on for this call */
        int sockfd;
@@ -503,6 +513,14 @@ struct chan_iax2_pvt {
        int amaflags;
        struct iax2_dpcache *dpentries;
        struct ast_variable *vars;
+       /* last received remote rr */
+       struct iax_rr remote_rr;
+       /* Current base time: (just for stats) */
+       int min;
+       /* Dropped frame count: (just for stats) */
+       int frames_dropped;
+       /* received frame count: (just for stats) */
+       int frames_received;
 };
 
 static struct ast_iax2_queue {
@@ -2074,6 +2092,9 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
                iaxs[fr->callno]->jitterbuffer = max 
                        /* + ((float)iaxs[fr->callno]->jitter) * 0.1 */;
 
+       /* update "min", just for RRs and stats */
+       iaxs[fr->callno]->min = min; 
+
        /* If the caller just wanted us to update, return now */
        if (!reallydeliver)
                return 0;
@@ -2111,6 +2132,7 @@ static int schedule_delivery(struct iax_frame *fr, int reallydeliver, int update
                } else {
                        if (option_debug)
                                ast_log(LOG_DEBUG, "schedule_delivery: Dropping voice packet since %dms delay is too old\n", delay);
+                       iaxs[fr->callno]->frames_dropped++;
                        /* Free our iax frame */
                        iax2_frame_free(fr);
                }
@@ -3902,6 +3924,50 @@ static int iax2_show_channels(int fd, int argc, char *argv[])
        return RESULT_SUCCESS;
 #undef FORMAT
 #undef FORMAT2
+#undef FORMATB
+}
+
+static int iax2_show_netstats(int fd, int argc, char *argv[])
+{
+       int x;
+       int numchans = 0;
+       if (argc != 3)
+               return RESULT_SHOWUSAGE;
+       ast_cli(fd, "                                -------- LOCAL ---------------------  -------- REMOTE --------------------\n");
+       ast_cli(fd, "Channel                    RTT  Jit  Del  Lost   %%  Drop  OOO  Kpkts  Jit  Del  Lost   %%  Drop  OOO  Kpkts\n");
+       for (x=0;x<IAX_MAX_CALLS;x++) {
+               ast_mutex_lock(&iaxsl[x]);
+               if (iaxs[x]) {
+#ifdef BRIDGE_OPTIMIZATION
+                       if (iaxs[x]->bridgecallno)
+                               ast_cli(fd, "%-25.25s <NATIVE BRIDGED>",
+                                               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)");
+                       else
+#endif
+                               ast_cli(fd, "%-25.25s %4d %4d %4d %5d %3d %5d %4d %6d %4d %4d %5d %3d %5d %4d %6d\n",
+                                               iaxs[x]->owner ? iaxs[x]->owner->name : "(None)",
+                                               iaxs[x]->pingtime,
+                                               iaxs[x]->jitter, 
+                                               ast_test_flag(iaxs[x], IAX_USEJITTERBUF) ? jitterbufsize(iaxs[x]) : 0,
+                                               -1,
+                                               -1,
+                                               -1,
+                                               -1,
+                                               iaxs[x]->frames_received/1000,
+                                               iaxs[x]->remote_rr.jitter,
+                                               iaxs[x]->remote_rr.delay,
+                                               iaxs[x]->remote_rr.losscnt,
+                                               iaxs[x]->remote_rr.losspct,
+                                               iaxs[x]->remote_rr.dropped,
+                                               iaxs[x]->remote_rr.ooo,
+                                               iaxs[x]->remote_rr.packets/1000
+                               );
+                       numchans++;
+               }
+               ast_mutex_unlock(&iaxsl[x]);
+       }
+       ast_cli(fd, "%d active IAX channel(s)\n", numchans);
+       return RESULT_SUCCESS;
 }
 
 static int iax2_do_trunk_debug(int fd, int argc, char *argv[])
@@ -3942,6 +4008,10 @@ static char show_channels_usage[] =
 "Usage: iax2 show channels\n"
 "       Lists all currently active IAX channels.\n";
 
+static char show_netstats_usage[] = 
+"Usage: iax2 show netstats\n"
+"       Lists network status for all currently active IAX channels.\n";
+
 static char show_peers_usage[] = 
 "Usage: iax2 show peers [registered] [pattern]\n"
 "       Lists all known IAX2 peers.\n"
@@ -3974,6 +4044,8 @@ static struct ast_cli_entry  cli_show_firmware =
        { { "iax2", "show", "firmware", NULL }, iax2_show_firmware, "Show available IAX firmwares", show_firmware_usage };
 static struct ast_cli_entry  cli_show_channels =
        { { "iax2", "show", "channels", NULL }, iax2_show_channels, "Show active IAX channels", show_channels_usage };
+static struct ast_cli_entry  cli_show_netstats =
+       { { "iax2", "show", "netstats", NULL }, iax2_show_netstats, "Show active IAX channel netstats", show_netstats_usage };
 static struct ast_cli_entry  cli_show_peers =
        { { "iax2", "show", "peers", NULL }, iax2_show_peers, "Show defined IAX peers", show_peers_usage };
 static struct ast_cli_entry  cli_show_registry =
@@ -5531,6 +5603,32 @@ static int check_provisioning(struct sockaddr_in *sin, char *si, unsigned int ve
        return 0;
 }
 
+static void construct_rr(struct chan_iax2_pvt *pvt, struct iax_ie_data *iep) 
+{
+       memset(iep, 0, sizeof(*iep));
+       iax_ie_append_int(iep,IAX_IE_RR_JITTER, pvt->jitter);
+       iax_ie_append_int(iep,IAX_IE_RR_PKTS, pvt->frames_received);
+       if(!ast_test_flag(pvt, IAX_USEJITTERBUF)) 
+           iax_ie_append_short(iep,IAX_IE_RR_DELAY, 0);
+       else
+           iax_ie_append_short(iep,IAX_IE_RR_DELAY, pvt->jitterbuffer - pvt->min);
+       iax_ie_append_int(iep,IAX_IE_RR_DROPPED, pvt->frames_dropped);
+       /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_OOO, 0); */
+       /* don't know, don't send! iax_ie_append_int(&ied,IAX_IE_RR_LOSS, 0); */
+
+}
+
+static void save_rr(struct iax_frame *fr, struct iax_ies *ies) 
+{
+       iaxs[fr->callno]->remote_rr.jitter = ies->rr_jitter;
+       iaxs[fr->callno]->remote_rr.losspct = ies->rr_loss >> 24;
+       iaxs[fr->callno]->remote_rr.losscnt = ies->rr_loss & 0xffffff;
+       iaxs[fr->callno]->remote_rr.packets = ies->rr_pkts;
+       iaxs[fr->callno]->remote_rr.delay = ies->rr_delay;
+       iaxs[fr->callno]->remote_rr.dropped = ies->rr_dropped;
+       iaxs[fr->callno]->remote_rr.ooo = ies->rr_ooo;
+}
+
 static int socket_read(int *id, int fd, short events, void *cbdata)
 {
        struct sockaddr_in sin;
@@ -5733,6 +5831,10 @@ static int socket_read(int *id, int fd, short events, void *cbdata)
                        iax_showframe(NULL, fh, 1, &sin, res - sizeof(struct ast_iax2_full_hdr));
 #endif
        }
+
+       /* count this frame */
+       iaxs[fr.callno]->frames_received++;
+
        if (!inaddrcmp(&sin, &iaxs[fr.callno]->addr) && !minivid &&
                f.subclass != IAX_COMMAND_TXCNT &&              /* for attended transfer */
                f.subclass != IAX_COMMAND_TXACC)                /* for attended transfer */
@@ -6268,12 +6370,18 @@ retryowner2:
                                        /* If we're in a bridged call, just forward this */
                                        forward_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PING, fr.ts, NULL, 0, -1);
                                } else {
+                                       struct iax_ie_data pingied;
+                                       construct_rr(iaxs[fr.callno], &pingied);
                                        /* Send back a pong packet with the original timestamp */
-                                       send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
+                                       send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, pingied.buf, pingied.pos, -1);
                                }
 #else                          
+                               {
+                                       struct iax_ie_data pingied;
+                                       construct_rr(iaxs[fr.callno], &pingied);
                                /* Send back a pong packet with the original timestamp */
-                               send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, NULL, 0, -1);
+                                       send_command(iaxs[fr.callno], AST_FRAME_IAX, IAX_COMMAND_PONG, fr.ts, pingied.buf, pingied.pos, -1);
+                               }
 #endif                 
                                break;
                        case IAX_COMMAND_PONG:
@@ -6289,6 +6397,9 @@ retryowner2:
                                /* Calculate ping time */
                                iaxs[fr.callno]->pingtime =  calc_timestamp(iaxs[fr.callno], 0, &f) - fr.ts;
 #endif
+                               /* save RR info */
+                               save_rr(&fr, &ies);
+
                                if (iaxs[fr.callno]->peerpoke) {
                                        peer = iaxs[fr.callno]->peerpoke;
                                        if ((peer->lastms < 0)  || (peer->lastms > peer->maxms)) {
@@ -8228,6 +8339,7 @@ static int __unload_module(void)
        ast_unregister_application(papp);
        ast_cli_unregister(&cli_show_users);
        ast_cli_unregister(&cli_show_channels);
+       ast_cli_unregister(&cli_show_netstats);
        ast_cli_unregister(&cli_show_peers);
        ast_cli_unregister(&cli_show_firmware);
        ast_cli_unregister(&cli_show_registry);
@@ -8308,6 +8420,7 @@ int load_module(void)
 
        ast_cli_register(&cli_show_users);
        ast_cli_register(&cli_show_channels);
+       ast_cli_register(&cli_show_netstats);
        ast_cli_register(&cli_show_peers);
        ast_cli_register(&cli_show_firmware);
        ast_cli_register(&cli_show_registry);
index e9cf2db..6adc684 100755 (executable)
@@ -228,6 +228,12 @@ static struct iax2_ie {
        { IAX_IE_ENCRYPTION, "ENCRYPTION", dump_short },
        { IAX_IE_ENCKEY, "ENCRYPTION KEY" },
        { IAX_IE_CODEC_PREFS, "CODEC_PREFS", dump_prefs },
+       { IAX_IE_RR_JITTER, "RR_JITTER", dump_int },
+       { IAX_IE_RR_LOSS, "RR_LOSS", dump_int },
+       { IAX_IE_RR_PKTS, "RR_PKTS", dump_int },
+       { IAX_IE_RR_DELAY, "RR_DELAY", dump_short },
+       { IAX_IE_RR_DROPPED, "RR_DROPPED", dump_int },
+       { IAX_IE_RR_OOO, "RR_OUTOFORDER", dump_int },
 };
 
 static struct iax2_ie prov_ies[] = {
@@ -784,6 +790,54 @@ int iax_parse_ies(struct iax_ies *ies, unsigned char *data, int datalen)
                        } else
                                ies->calling_tns = ntohs(get_uint16(data + 2)); 
                        break;
+               case IAX_IE_RR_JITTER:
+                       if (len != (int)sizeof(unsigned int)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected jitter rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else {
+                               ies->rr_jitter = ntohl(get_uint32(data + 2));
+                       }
+                       break;
+               case IAX_IE_RR_LOSS:
+                       if (len != (int)sizeof(unsigned int)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else {
+                               ies->rr_loss = ntohl(get_uint32(data + 2));
+                       }
+                       break;
+               case IAX_IE_RR_PKTS:
+                       if (len != (int)sizeof(unsigned int)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else {
+                               ies->rr_pkts = ntohl(get_uint32(data + 2));
+                       }
+                       break;
+               case IAX_IE_RR_DELAY:
+                       if (len != (int)sizeof(unsigned short)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected loss rr to be %d bytes long but was %d\n", (int)sizeof(unsigned short), len);
+                        errorf(tmp);
+                       } else {
+                               ies->rr_delay = ntohs(get_uint16(data + 2));
+                       }
+                       break;
+               case IAX_IE_RR_DROPPED:
+                       if (len != (int)sizeof(unsigned int)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else {
+                               ies->rr_dropped = ntohl(get_uint32(data + 2));
+                       }
+                       break;
+               case IAX_IE_RR_OOO:
+                       if (len != (int)sizeof(unsigned int)) {
+                               snprintf(tmp, (int)sizeof(tmp), "Expected packets rr to be %d bytes long but was %d\n", (int)sizeof(unsigned int), len);
+                               errorf(tmp);
+                       } else {
+                               ies->rr_ooo = ntohl(get_uint32(data + 2));
+                       }
+                       break;
                default:
                        snprintf(tmp, (int)sizeof(tmp), "Ignoring unknown information element '%s' (%d) of length %d\n", iax_ie2str(ie), ie, len);
                        outputf(tmp);
index 691c8aa..909360f 100755 (executable)
@@ -61,6 +61,12 @@ struct iax_ies {
        unsigned int provver;
        unsigned short samprate;
        int provverpres;
+       unsigned int rr_jitter;
+       unsigned int rr_loss;
+       unsigned int rr_pkts;
+       unsigned short rr_delay;
+       unsigned int rr_dropped;
+       unsigned int rr_ooo;
 };
 
 #define DIRECTION_INGRESS 1
index a19c671..4e71c76 100755 (executable)
 #define IAX_IE_ENCKEY                          44              /* Encryption key (raw) */
 #define IAX_IE_CODEC_PREFS          45      /* Codec Negotiation */
 
+#define IAX_IE_RR_JITTER                       46              /* Received jitter (as in RFC1889) u32 */
+#define IAX_IE_RR_LOSS                         47              /* Received loss (high byte loss pct, low 24 bits loss count, as in rfc1889 */
+#define IAX_IE_RR_PKTS                         48              /* Received frames (total frames received) u32 */
+#define IAX_IE_RR_DELAY                                49              /* Max playout delay for received frames (in ms) u16 */
+#define IAX_IE_RR_DROPPED                      50              /* Dropped frames (presumably by jitterbuf) u32 */
+#define IAX_IE_RR_OOO                          51              /* Frames received Out of Order u32 */
+
+
 #define IAX_AUTH_PLAINTEXT                     (1 << 0)
 #define IAX_AUTH_MD5                           (1 << 1)
 #define IAX_AUTH_RSA                           (1 << 2)