cf: Add a keybinding to only display active RTP streams

We consider an active RTP stream those that have received a RTP packet
in the last STREAM_INACTIVE_SECS seconds (which defaults to 3). This is
a bit adhoc display that requires testing.
This commit is contained in:
Kaian 2016-12-19 12:01:17 +01:00
parent b7fb904b40
commit 4aacd31211
7 changed files with 82 additions and 11 deletions

View File

@ -650,7 +650,8 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
if (address_equals(msg->packet->src, stream->dst)) { if (address_equals(msg->packet->src, stream->dst)) {
// Reuse the msg arrow columns as destination column // Reuse the msg arrow columns as destination column
if ((msgarrow = call_flow_arrow_find(ui, msg))) { if ((msgarrow = call_flow_arrow_find(ui, msg))) {
arrow->dcolumn = msgarrow->scolumn; // Get origin and destination column
arrow->dcolumn = call_flow_column_get(ui, msg->call->callid, msg->packet->src);
} }
} }
@ -674,7 +675,20 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
if (msg && address_equals(msg->packet->src, stream->src)) { if (msg && address_equals(msg->packet->src, stream->src)) {
// Reuse the msg arrow columns as destination column // Reuse the msg arrow columns as destination column
if ((msgarrow = call_flow_arrow_find(ui, msg))) { if ((msgarrow = call_flow_arrow_find(ui, msg))) {
arrow->scolumn = msgarrow->scolumn; // Get origin and destination column
arrow->scolumn = call_flow_column_get(ui, msg->call->callid, msg->packet->src);
}
}
// Prefer message that configured this stream rather than any column
if (!arrow->scolumn) {
msg = stream->media->msg;
// If message and stream share the same IP address
if (address_equals(msg->packet->dst, stream->src)) {
// Reuse the msg arrow columns as destination column
if ((msgarrow = call_flow_arrow_find(ui, msg))) {
arrow->scolumn = call_flow_column_get(ui, msg->call->callid, msg->packet->dst);
}
} }
} }
@ -734,16 +748,23 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
} }
} }
// Check if displayed stream is active
int active = stream_is_active(stream);
// Clear the line // Clear the line
mvwprintw(win, cline, startpos + 2, "%*s", distance, ""); mvwprintw(win, cline, startpos + 2, "%*s", distance, "");
// Draw method // Draw RTP arrow text
mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text); mvwprintw(win, cline, startpos + (distance) / 2 - strlen(text) / 2 + 2, "%s", text);
if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
cline++; cline++;
// Draw line between columns // Draw line between columns
mvwhline(win, cline, startpos + 2, ACS_HLINE, distance); if (active)
mvwhline(win, cline, startpos + 2, '-', distance);
else
mvwhline(win, cline, startpos + 2, ACS_HLINE, distance);
// Write the arrow at the end of the message (two arrows if this is a retrans) // Write the arrow at the end of the message (two arrows if this is a retrans)
if (arrow_dir == CF_ARROW_RIGHT) { if (arrow_dir == CF_ARROW_RIGHT) {
if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) { if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) {
@ -751,7 +772,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
mvwprintw(win, cline, endpos, "%d", stream->dst.port); mvwprintw(win, cline, endpos, "%d", stream->dst.port);
} }
mvwaddch(win, cline, endpos - 2, '>'); mvwaddch(win, cline, endpos - 2, '>');
if (arrow->rtp_count != stream_get_count(stream)) { if (active) {
arrow->rtp_count = stream_get_count(stream); arrow->rtp_count = stream_get_count(stream);
arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance;
mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>'); mvwaddch(win, cline, startpos + arrow->rtp_ind_pos + 2, '>');
@ -762,7 +783,7 @@ call_flow_draw_rtp_stream(ui_t *ui, call_flow_arrow_t *arrow, int cline)
mvwprintw(win, cline, startpos - 4, "%d", stream->dst.port); mvwprintw(win, cline, startpos - 4, "%d", stream->dst.port);
} }
mvwaddch(win, cline, startpos + 2, '<'); mvwaddch(win, cline, startpos + 2, '<');
if (arrow->rtp_count != stream_get_count(stream)) { if (active) {
arrow->rtp_count = stream_get_count(stream); arrow->rtp_count = stream_get_count(stream);
arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance;
mvwaddch(win, cline, endpos - arrow->rtp_ind_pos - 2, '<'); mvwaddch(win, cline, endpos - arrow->rtp_ind_pos - 2, '<');
@ -814,6 +835,8 @@ int
call_flow_arrow_height(ui_t *ui, const call_flow_arrow_t *arrow) call_flow_arrow_height(ui_t *ui, const call_flow_arrow_t *arrow)
{ {
if (arrow->type == CF_ARROW_SIP) { if (arrow->type == CF_ARROW_SIP) {
if (setting_enabled(SETTING_CF_ONLYMEDIA))
return 0;
if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) if (setting_has_value(SETTING_CF_SDP_INFO, "compressed"))
return 1; return 1;
if (!msg_has_sdp(arrow->item)) if (!msg_has_sdp(arrow->item))
@ -921,7 +944,7 @@ call_flow_draw_raw(ui_t *ui, sip_msg_t *msg)
info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0); info->raw_win = raw_win = newwin(raw_height, raw_width, 0, 0);
} }
// Draw raw box lines // Draw raw box li
wattron(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF)); wattron(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF));
mvwvline(ui->win, 1, ui->width - raw_width - 2, ACS_VLINE, ui->height - 2); mvwvline(ui->win, 1, ui->width - raw_width - 2, ACS_VLINE, ui->height - 2);
wattroff(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF)); wattroff(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF));
@ -939,6 +962,11 @@ call_flow_draw_raw(ui_t *ui, sip_msg_t *msg)
int int
call_flow_draw_raw_rtcp(ui_t *ui, rtp_stream_t *stream) call_flow_draw_raw_rtcp(ui_t *ui, rtp_stream_t *stream)
{ {
/**
* TODO This is too experimental to even display it
*/
return 0;
call_flow_info_t *info; call_flow_info_t *info;
WINDOW *raw_win; WINDOW *raw_win;
int raw_width, raw_height; int raw_width, raw_height;
@ -1094,6 +1122,10 @@ call_flow_handle_key(ui_t *ui, int key)
case ACTION_SDP_INFO: case ACTION_SDP_INFO:
setting_toggle(SETTING_CF_SDP_INFO); setting_toggle(SETTING_CF_SDP_INFO);
break; break;
case ACTION_ONLY_MEDIA:
setting_toggle(SETTING_CF_ONLYMEDIA);
call_flow_set_group(info->group);
break;
case ACTION_TOGGLE_MEDIA: case ACTION_TOGGLE_MEDIA:
setting_toggle(SETTING_CF_MEDIA); setting_toggle(SETTING_CF_MEDIA);
// Force reload arrows // Force reload arrows
@ -1463,12 +1495,18 @@ call_flow_arrow_filter(void *item)
call_flow_arrow_t *arrow = (call_flow_arrow_t *) item; call_flow_arrow_t *arrow = (call_flow_arrow_t *) item;
// SIP arrows are never filtered // SIP arrows are never filtered
if (arrow->type == CF_ARROW_SIP) if (arrow->type == CF_ARROW_SIP && setting_disabled(SETTING_CF_ONLYMEDIA))
return 1; return 1;
// RTP arrows are only displayed when requested // RTP arrows are only displayed when requested
if (arrow->type == CF_ARROW_RTP && setting_enabled(SETTING_CF_MEDIA)) if (arrow->type == CF_ARROW_RTP) {
return 1; // Display all streams
if (setting_enabled(SETTING_CF_MEDIA))
return 1;
// Otherwise only show active streams
if (setting_has_value(SETTING_CF_MEDIA, SETTING_ACTIVE))
return stream_is_active(arrow->item);
}
// Rest of the arrows are never displayed // Rest of the arrows are never displayed
return 0; return 0;

View File

@ -77,6 +77,7 @@ key_binding_t bindings[ACTION_SENTINEL] = {
{ ACTION_SELECT, "select", { KEY_SPACE }, 1 }, { ACTION_SELECT, "select", { KEY_SPACE }, 1 },
{ ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 }, { ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 },
{ ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 }, { ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 },
{ ACTION_ONLY_MEDIA, "onlymedia", { 'M' }, 1 },
{ ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 }, { ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 },
{ ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 }, { ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 },
{ ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 }, { ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 },

View File

@ -97,6 +97,7 @@ enum key_actions {
ACTION_SELECT, ACTION_SELECT,
ACTION_CONFIRM, ACTION_CONFIRM,
ACTION_TOGGLE_MEDIA, ACTION_TOGGLE_MEDIA,
ACTION_ONLY_MEDIA,
ACTION_TOGGLE_RAW, ACTION_TOGGLE_RAW,
ACTION_INCREASE_RAW, ACTION_INCREASE_RAW,
ACTION_DECREASE_RAW, ACTION_DECREASE_RAW,

View File

@ -29,6 +29,9 @@
* *
*/ */
#include "config.h"
#include <stddef.h>
#include <time.h>
#include "rtp.h" #include "rtp.h"
#include "sip.h" #include "sip.h"
#include "vector.h" #include "vector.h"
@ -100,6 +103,7 @@ stream_add_packet(rtp_stream_t *stream, packet_t *packet)
if (stream->pktcnt == 0) if (stream->pktcnt == 0)
stream->time = packet_time(packet); stream->time = packet_time(packet);
stream->lasttm = (int) time(NULL);
stream->pktcnt++; stream->pktcnt++;
} }
@ -472,6 +476,12 @@ stream_is_complete(rtp_stream_t *stream)
return (stream->pktcnt != 0); return (stream->pktcnt != 0);
} }
int
stream_is_active(rtp_stream_t *stream)
{
return ((int) time(NULL) - stream->lasttm <= STREAM_INACTIVE_SECS);
}
int int
data_is_rtp(u_char *data, uint32_t len) data_is_rtp(u_char *data, uint32_t len)
{ {

View File

@ -50,6 +50,9 @@
// RTCP common header length // RTCP common header length
#define RTCP_HDR_LENGTH 4 #define RTCP_HDR_LENGTH 4
// If stream does not receive a packet in this seconds, we consider it inactive
#define STREAM_INACTIVE_SECS 3
// RTCP header types // RTCP header types
//! http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml //! http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml
enum rtcp_header_types enum rtcp_header_types
@ -108,6 +111,8 @@ struct rtp_stream {
uint32_t pktcnt; uint32_t pktcnt;
//! Time of first received packet of stream //! Time of first received packet of stream
struct timeval time; struct timeval time;
//! Unix timestamp of last received packet
int lasttm;
// Stream information (depending on type) // Stream information (depending on type)
union { union {
@ -321,6 +326,18 @@ stream_is_older(rtp_stream_t *one, rtp_stream_t *two);
int int
stream_is_complete(rtp_stream_t *stream); stream_is_complete(rtp_stream_t *stream);
/**
* @brief Determine if a stream is still active
*
* This simply checks the timestamp of the last received packet of the stream
* marking as inactive if it was before STREAM_INACTIVE_SECS ago
*
* @return 1 if stream is active
* @return 0 if stream is inactive
*/
int
stream_is_active(rtp_stream_t *stream);
/** /**
* @brief Check if the data is a RTP packet * @brief Check if the data is a RTP packet
* RFC 5761 Section 4. Distinguishable RTP and RTCP Packets * RFC 5761 Section 4. Distinguishable RTP and RTCP Packets

View File

@ -67,7 +67,8 @@ setting_t settings[SETTING_COUNT] = {
{ SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL }, { SETTING_CF_SCROLLSTEP, "cf.scrollstep", SETTING_FMT_NUMBER, "4", NULL },
{ SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CF_LOCALHIGHLIGHT, "cf.localhighlight", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_SDP_INFO }, { SETTING_CF_SDP_INFO, "cf.sdpinfo", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_SDP_INFO },
{ SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF }, { SETTING_CF_MEDIA, "cf.media", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_MEDIA },
{ SETTING_CF_ONLYMEDIA, "cf.onlymedia", SETTING_FMT_ENUM, SETTING_OFF, SETTING_ENUM_ONOFF },
{ SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF }, { SETTING_CF_DELTA, "cf.deltatime", SETTING_FMT_ENUM, SETTING_ON, SETTING_ENUM_ONOFF },
{ SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL }, { SETTING_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL },
{ SETTING_FILTER_PAYLOAD, "filter.payload", SETTING_FMT_STRING, "", NULL }, { SETTING_FILTER_PAYLOAD, "filter.payload", SETTING_FMT_STRING, "", NULL },

View File

@ -56,12 +56,14 @@ typedef struct setting_option setting_t;
#define SETTING_ENUM_SDP_INFO (const char *[]){ "off", "first", "full", "compressed", NULL} #define SETTING_ENUM_SDP_INFO (const char *[]){ "off", "first", "full", "compressed", NULL}
#define SETTING_ENUM_STORAGE (const char *[]){ "none", "memory", NULL } #define SETTING_ENUM_STORAGE (const char *[]){ "none", "memory", NULL }
#define SETTING_ENUM_HEPVERSION (const char *[]){ "2", "3", NULL } #define SETTING_ENUM_HEPVERSION (const char *[]){ "2", "3", NULL }
#define SETTING_ENUM_MEDIA (const char *[]){ "off", "on", "active", NULL }
//! Other useful defines //! Other useful defines
#define SETTING_ON "on" #define SETTING_ON "on"
#define SETTING_OFF "off" #define SETTING_OFF "off"
#define SETTING_YES "yes" #define SETTING_YES "yes"
#define SETTING_NO "no" #define SETTING_NO "no"
#define SETTING_ACTIVE "active"
//! Available setting Options //! Available setting Options
@ -98,6 +100,7 @@ enum setting_id {
SETTING_CF_LOCALHIGHLIGHT, SETTING_CF_LOCALHIGHLIGHT,
SETTING_CF_SDP_INFO, SETTING_CF_SDP_INFO,
SETTING_CF_MEDIA, SETTING_CF_MEDIA,
SETTING_CF_ONLYMEDIA,
SETTING_CF_DELTA, SETTING_CF_DELTA,
SETTING_CR_SCROLLSTEP, SETTING_CR_SCROLLSTEP,
SETTING_FILTER_PAYLOAD, SETTING_FILTER_PAYLOAD,