From 4aacd31211ea035f934841858d868117262f3939 Mon Sep 17 00:00:00 2001 From: Kaian Date: Mon, 19 Dec 2016 12:01:17 +0100 Subject: [PATCH] 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. --- src/curses/ui_call_flow.c | 58 ++++++++++++++++++++++++++++++++------- src/keybinding.c | 1 + src/keybinding.h | 1 + src/rtp.c | 10 +++++++ src/rtp.h | 17 ++++++++++++ src/setting.c | 3 +- src/setting.h | 3 ++ 7 files changed, 82 insertions(+), 11 deletions(-) diff --git a/src/curses/ui_call_flow.c b/src/curses/ui_call_flow.c index c5533f0..bd174ac 100644 --- a/src/curses/ui_call_flow.c +++ b/src/curses/ui_call_flow.c @@ -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)) { // Reuse the msg arrow columns as destination column 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)) { // Reuse the msg arrow columns as destination column 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 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); if (!setting_has_value(SETTING_CF_SDP_INFO, "compressed")) cline++; // 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) if (arrow_dir == CF_ARROW_RIGHT) { 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); } mvwaddch(win, cline, endpos - 2, '>'); - if (arrow->rtp_count != stream_get_count(stream)) { + if (active) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; 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); } mvwaddch(win, cline, startpos + 2, '<'); - if (arrow->rtp_count != stream_get_count(stream)) { + if (active) { arrow->rtp_count = stream_get_count(stream); arrow->rtp_ind_pos = (arrow->rtp_ind_pos + 1) % distance; 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) { if (arrow->type == CF_ARROW_SIP) { + if (setting_enabled(SETTING_CF_ONLYMEDIA)) + return 0; if (setting_has_value(SETTING_CF_SDP_INFO, "compressed")) return 1; 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); } - // Draw raw box lines + // Draw raw box li wattron(ui->win, COLOR_PAIR(CP_BLUE_ON_DEF)); mvwvline(ui->win, 1, ui->width - raw_width - 2, ACS_VLINE, ui->height - 2); 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 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; WINDOW *raw_win; int raw_width, raw_height; @@ -1094,6 +1122,10 @@ call_flow_handle_key(ui_t *ui, int key) case ACTION_SDP_INFO: setting_toggle(SETTING_CF_SDP_INFO); break; + case ACTION_ONLY_MEDIA: + setting_toggle(SETTING_CF_ONLYMEDIA); + call_flow_set_group(info->group); + break; case ACTION_TOGGLE_MEDIA: setting_toggle(SETTING_CF_MEDIA); // Force reload arrows @@ -1463,12 +1495,18 @@ call_flow_arrow_filter(void *item) call_flow_arrow_t *arrow = (call_flow_arrow_t *) item; // SIP arrows are never filtered - if (arrow->type == CF_ARROW_SIP) + if (arrow->type == CF_ARROW_SIP && setting_disabled(SETTING_CF_ONLYMEDIA)) return 1; // RTP arrows are only displayed when requested - if (arrow->type == CF_ARROW_RTP && setting_enabled(SETTING_CF_MEDIA)) - return 1; + if (arrow->type == CF_ARROW_RTP) { + // 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 return 0; diff --git a/src/keybinding.c b/src/keybinding.c index 367dfd1..400a390 100644 --- a/src/keybinding.c +++ b/src/keybinding.c @@ -77,6 +77,7 @@ key_binding_t bindings[ACTION_SENTINEL] = { { ACTION_SELECT, "select", { KEY_SPACE }, 1 }, { ACTION_CONFIRM, "confirm", { KEY_INTRO }, 1 }, { ACTION_TOGGLE_MEDIA, "togglemedia", { KEY_F(3), 'm' }, 2 }, + { ACTION_ONLY_MEDIA, "onlymedia", { 'M' }, 1 }, { ACTION_TOGGLE_RAW, "rawpreview", { 't' }, 1 }, { ACTION_INCREASE_RAW, "morerawpreview", { '9' }, 1 }, { ACTION_DECREASE_RAW, "lessrawpreview", { '0' }, 1 }, diff --git a/src/keybinding.h b/src/keybinding.h index 92b4523..46203b9 100644 --- a/src/keybinding.h +++ b/src/keybinding.h @@ -97,6 +97,7 @@ enum key_actions { ACTION_SELECT, ACTION_CONFIRM, ACTION_TOGGLE_MEDIA, + ACTION_ONLY_MEDIA, ACTION_TOGGLE_RAW, ACTION_INCREASE_RAW, ACTION_DECREASE_RAW, diff --git a/src/rtp.c b/src/rtp.c index 6cb12a3..1103fbe 100644 --- a/src/rtp.c +++ b/src/rtp.c @@ -29,6 +29,9 @@ * */ +#include "config.h" +#include +#include #include "rtp.h" #include "sip.h" #include "vector.h" @@ -100,6 +103,7 @@ stream_add_packet(rtp_stream_t *stream, packet_t *packet) if (stream->pktcnt == 0) stream->time = packet_time(packet); + stream->lasttm = (int) time(NULL); stream->pktcnt++; } @@ -472,6 +476,12 @@ stream_is_complete(rtp_stream_t *stream) return (stream->pktcnt != 0); } +int +stream_is_active(rtp_stream_t *stream) +{ + return ((int) time(NULL) - stream->lasttm <= STREAM_INACTIVE_SECS); +} + int data_is_rtp(u_char *data, uint32_t len) { diff --git a/src/rtp.h b/src/rtp.h index cfcd7ac..6c9bcc1 100644 --- a/src/rtp.h +++ b/src/rtp.h @@ -50,6 +50,9 @@ // RTCP common header length #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 //! http://www.iana.org/assignments/rtp-parameters/rtp-parameters.xhtml enum rtcp_header_types @@ -108,6 +111,8 @@ struct rtp_stream { uint32_t pktcnt; //! Time of first received packet of stream struct timeval time; + //! Unix timestamp of last received packet + int lasttm; // Stream information (depending on type) union { @@ -321,6 +326,18 @@ stream_is_older(rtp_stream_t *one, rtp_stream_t *two); int 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 * RFC 5761 Section 4. Distinguishable RTP and RTCP Packets diff --git a/src/setting.c b/src/setting.c index a108b1a..4343f1d 100644 --- a/src/setting.c +++ b/src/setting.c @@ -67,7 +67,8 @@ setting_t settings[SETTING_COUNT] = { { 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_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_CR_SCROLLSTEP, "cr.scrollstep", SETTING_FMT_NUMBER, "10", NULL }, { SETTING_FILTER_PAYLOAD, "filter.payload", SETTING_FMT_STRING, "", NULL }, diff --git a/src/setting.h b/src/setting.h index cadbfeb..492a9a7 100644 --- a/src/setting.h +++ b/src/setting.h @@ -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_STORAGE (const char *[]){ "none", "memory", NULL } #define SETTING_ENUM_HEPVERSION (const char *[]){ "2", "3", NULL } +#define SETTING_ENUM_MEDIA (const char *[]){ "off", "on", "active", NULL } //! Other useful defines #define SETTING_ON "on" #define SETTING_OFF "off" #define SETTING_YES "yes" #define SETTING_NO "no" +#define SETTING_ACTIVE "active" //! Available setting Options @@ -98,6 +100,7 @@ enum setting_id { SETTING_CF_LOCALHIGHLIGHT, SETTING_CF_SDP_INFO, SETTING_CF_MEDIA, + SETTING_CF_ONLYMEDIA, SETTING_CF_DELTA, SETTING_CR_SCROLLSTEP, SETTING_FILTER_PAYLOAD,