diff --git a/daemon/rtcp.c b/daemon/rtcp.c index 018f8a076..d636c7511 100644 --- a/daemon/rtcp.c +++ b/daemon/rtcp.c @@ -513,6 +513,13 @@ static void print_rtcp_rr_list_start(pjmedia_rtcp_common *common, GString *json) common->count); } +static void print_rtcp_sdes_list_start(pjmedia_rtcp_common *common, GString *json) { + if (json) + g_string_append_printf(json, "\"sdes_ssrc\":%u,\"sdes_report_count\":%u,\"sdes_information\": [ ", + ntohl(common->ssrc), + common->count); +} + static void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, GString *json) { /* Get packet loss */ u_int32_t packet_loss=0; @@ -543,12 +550,55 @@ static void print_rtcp_rr(GString *log, const pjmedia_rtcp_rr* rr, GString *json ntohl(rr->dlsr)); } +static void print_rtcp_sdes_item(GString *json, const rtcp_sdes_chunk_t *chunk, const rtcp_sdes_item_t *item, + const char *data) +{ + int i; + + if (json) { + g_string_append_printf(json, "{\"sdes_chunk_ssrc\":%u,\"type\":%u,\"text\":\"", + htonl(chunk->csrc), + item->type); + + for (i = 0; i < item->len; i++) { + switch (data[i]) { + case '"': + g_string_append(json, "\\\""); + break; + case '\\': + g_string_append(json, "\\\\"); + break; + case '\b': + g_string_append(json, "\\b"); + break; + case '\f': + g_string_append(json, "\\f"); + break; + case '\n': + g_string_append(json, "\\n"); + break; + case '\r': + g_string_append(json, "\\r"); + break; + case '\t': + g_string_append(json, "\\t"); + break; + default: + g_string_append_c(json, data[i]); + break; + } + } + + g_string_append(json, "\"},"); + } +} + static void str_sanitize(GString *s) { while (s->len > 0 && (s->str[s->len - 1] == ' ' || s->str[s->len - 1] == ',')) g_string_truncate(s, s->len - 1); } -static void print_rtcp_rr_list_end(pjmedia_rtcp_common *common, GString *json) { +static void print_rtcp_list_end(GString *json) { if (json) { str_sanitize(json); g_string_append_printf(json, "],"); @@ -560,8 +610,10 @@ void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *ori_s, const en GString *log; str iter_s, comp_s; pjmedia_rtcp_common *common; - const pjmedia_rtcp_rr *rr = NULL; - const pjmedia_rtcp_sr *sr = NULL; + const pjmedia_rtcp_rr *rr; + const pjmedia_rtcp_sr *sr; + const rtcp_sdes_chunk_t *sdes_chunk; + const rtcp_sdes_item_t *sdes_item; GString *json; struct call *c = sfd->call; struct callmaster *cm = c->callmaster; @@ -615,12 +667,56 @@ void parse_and_log_rtcp_report(struct stream_fd *sfd, const str *ori_s, const en print_rtcp_rr(log, rr, json); } - print_rtcp_rr_list_end(common, json); + print_rtcp_list_end(json); break; case RTCP_PT_XR: pjmedia_rtcp_xr_rx_rtcp_xr(log, common, &comp_s); break; + + case RTCP_PT_SDES: + print_rtcp_sdes_list_start(common, json); + + // the "common" header actually includes the SDES + // SSRC/CSRC chunk header, so we set our chunk header + // to its SDES field + sdes_chunk = (rtcp_sdes_chunk_t *) &common->ssrc; + // comp_s then points into the first SDES item + + i = 0; + while (1) { + while (comp_s.len) { + sdes_item = (rtcp_sdes_item_t *) comp_s.s; + // check for zero type first + if (str_shift(&comp_s, 1)) + break; + if (!sdes_item->type) + break; + if (str_shift(&comp_s, sizeof(*sdes_item) - 1)) + break; + if (comp_s.len < sdes_item->len) + break; + print_rtcp_sdes_item(json, sdes_chunk, sdes_item, comp_s.s); + str_shift(&comp_s, sdes_item->len); + } + + // remove padding to next chunk + while (comp_s.len % 4 != 0) + str_shift(&comp_s, 1); + + // more chunks? set chunk header + i++; + if (i >= common->count) + break; + sdes_chunk = (rtcp_sdes_chunk_t *) comp_s.s; + if (str_shift(&comp_s, sizeof(*sdes_chunk))) + break; + + } + + print_rtcp_list_end(json); + + break; } } diff --git a/daemon/rtcp.h b/daemon/rtcp.h index 3bd9d8352..cd5c16431 100644 --- a/daemon/rtcp.h +++ b/daemon/rtcp.h @@ -60,6 +60,18 @@ typedef struct pjmedia_rtcp_rr } __attribute__ ((packed)) pjmedia_rtcp_rr; +typedef struct _rtcp_sdes_chunk +{ + uint32_t csrc; +} __attribute__ ((packed)) rtcp_sdes_chunk_t; + +typedef struct _rtcp_sdes_item +{ + uint8_t type; + uint8_t len; +} __attribute__ ((packed)) rtcp_sdes_item_t; + + /** * RTCP common header. */ diff --git a/tests/simulator-ng.pl b/tests/simulator-ng.pl index 983081ac7..10f416f3e 100755 --- a/tests/simulator-ng.pl +++ b/tests/simulator-ng.pl @@ -229,6 +229,24 @@ sub rtcp_sr { 12345, rand(12345), rand(4321)); $sr .= pack('N CCCC NNNN', rand(2**32), rand(256), rand(256), rand(256), rand(256), rand(2**32), rand(2**32), rand(2**32), rand(2**32)); + # sdes + $sr .= pack('CCn N CC a* CC a* CC a* C C N CC a* CC a* C CCC N CC a* C', + (2 << 6) | 3, 202, 16, + rand(2 ** 32), # csrc + 1, 7, 'blah123', # cname + 2, 6, 'foobar', # name + 3, 7, 'foo@bar', # email, + 0, # eol + 0, # padding + rand(2 ** 32), # csrc + 4, 5, '54321', # phone + 5, 3, 'foo', # loc + 0, # eol + 0,0,0, # padding + rand(2 ** 32), # csrc + 6, 5, 'fubar', # tool + 0, # eol + ); return $sr; }