|
|
@ -15,6 +15,7 @@ |
|
|
#include "homer.h" |
|
|
#include "homer.h" |
|
|
#include "media_socket.h" |
|
|
#include "media_socket.h" |
|
|
#include "rtcplib.h" |
|
|
#include "rtcplib.h" |
|
|
|
|
|
#include "ssrc.h" |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -133,7 +134,17 @@ struct rtcp_chain_element { |
|
|
// struct defs |
|
|
// struct defs |
|
|
// context to hold state variables |
|
|
// context to hold state variables |
|
|
struct rtcp_process_ctx { |
|
|
struct rtcp_process_ctx { |
|
|
u_int32_t scratch; |
|
|
|
|
|
|
|
|
// input |
|
|
|
|
|
struct call *call; |
|
|
|
|
|
const struct timeval *received; |
|
|
|
|
|
|
|
|
|
|
|
// handler vars |
|
|
|
|
|
union { |
|
|
|
|
|
struct ssrc_receiver_report rr; |
|
|
|
|
|
struct ssrc_sender_report sr; |
|
|
|
|
|
} scratch; |
|
|
|
|
|
u_int32_t scratch_common_ssrc; |
|
|
|
|
|
|
|
|
GString *log; |
|
|
GString *log; |
|
|
GString *json; |
|
|
GString *json; |
|
|
}; |
|
|
}; |
|
|
@ -159,6 +170,7 @@ struct rtcp_handler { |
|
|
struct rtcp_handlers { |
|
|
struct rtcp_handlers { |
|
|
const struct rtcp_handler |
|
|
const struct rtcp_handler |
|
|
*scratch, |
|
|
*scratch, |
|
|
|
|
|
*mos, |
|
|
*logging, |
|
|
*logging, |
|
|
*homer; |
|
|
*homer; |
|
|
}; |
|
|
}; |
|
|
@ -167,8 +179,14 @@ struct rtcp_handlers { |
|
|
static void dummy_handler(); |
|
|
static void dummy_handler(); |
|
|
|
|
|
|
|
|
// scratch area (prepare/parse packet) |
|
|
// scratch area (prepare/parse packet) |
|
|
|
|
|
static void scratch_common(struct rtcp_process_ctx *, const struct rtcp_packet *); |
|
|
|
|
|
static void scratch_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); |
|
|
static void scratch_rr(struct rtcp_process_ctx *, const struct report_block *); |
|
|
static void scratch_rr(struct rtcp_process_ctx *, const struct report_block *); |
|
|
|
|
|
|
|
|
|
|
|
// MOS calculation / stats |
|
|
|
|
|
static void mos_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); |
|
|
|
|
|
static void mos_rr(struct rtcp_process_ctx *, const struct report_block *); |
|
|
|
|
|
|
|
|
// homer functions |
|
|
// homer functions |
|
|
static void homer_init(struct rtcp_process_ctx *); |
|
|
static void homer_init(struct rtcp_process_ctx *); |
|
|
static void homer_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); |
|
|
static void homer_sr(struct rtcp_process_ctx *, const struct sender_report_packet *); |
|
|
@ -197,7 +215,13 @@ static void logging_destroy(struct rtcp_process_ctx *); |
|
|
// structs for each handler type |
|
|
// structs for each handler type |
|
|
static struct rtcp_handler dummy_handlers; |
|
|
static struct rtcp_handler dummy_handlers; |
|
|
static struct rtcp_handler scratch_handlers = { |
|
|
static struct rtcp_handler scratch_handlers = { |
|
|
|
|
|
.common = scratch_common, |
|
|
.rr = scratch_rr, |
|
|
.rr = scratch_rr, |
|
|
|
|
|
.sr = scratch_sr, |
|
|
|
|
|
}; |
|
|
|
|
|
static struct rtcp_handler mos_handlers = { |
|
|
|
|
|
.rr = mos_rr, |
|
|
|
|
|
.sr = mos_sr, |
|
|
}; |
|
|
}; |
|
|
static struct rtcp_handler log_handlers = { |
|
|
static struct rtcp_handler log_handlers = { |
|
|
.init = logging_init, |
|
|
.init = logging_init, |
|
|
@ -225,12 +249,15 @@ static struct rtcp_handler homer_handlers = { |
|
|
// main var to hold references |
|
|
// main var to hold references |
|
|
static struct rtcp_handlers rtcp_handlers = { |
|
|
static struct rtcp_handlers rtcp_handlers = { |
|
|
.scratch = &scratch_handlers, |
|
|
.scratch = &scratch_handlers, |
|
|
|
|
|
.mos = &mos_handlers, |
|
|
|
|
|
// remainder is variable |
|
|
}; |
|
|
}; |
|
|
|
|
|
|
|
|
// list of all handlers |
|
|
// list of all handlers |
|
|
static struct rtcp_handler *all_handlers[] = { |
|
|
static struct rtcp_handler *all_handlers[] = { |
|
|
&dummy_handlers, |
|
|
&dummy_handlers, |
|
|
&scratch_handlers, |
|
|
&scratch_handlers, |
|
|
|
|
|
&mos_handlers, |
|
|
&log_handlers, |
|
|
&log_handlers, |
|
|
&homer_handlers, |
|
|
&homer_handlers, |
|
|
}; |
|
|
}; |
|
|
@ -238,6 +265,7 @@ static struct rtcp_handler *all_handlers[] = { |
|
|
// macro to call all function handlers in one go |
|
|
// macro to call all function handlers in one go |
|
|
#define CAH(func, ...) do { \ |
|
|
#define CAH(func, ...) do { \ |
|
|
rtcp_handlers.scratch->func(log_ctx, ##__VA_ARGS__); \ |
|
|
rtcp_handlers.scratch->func(log_ctx, ##__VA_ARGS__); \ |
|
|
|
|
|
rtcp_handlers.mos->func(log_ctx, ##__VA_ARGS__); \ |
|
|
rtcp_handlers.logging->func(log_ctx, ##__VA_ARGS__); \ |
|
|
rtcp_handlers.logging->func(log_ctx, ##__VA_ARGS__); \ |
|
|
rtcp_handlers.homer->func(log_ctx, ##__VA_ARGS__); \ |
|
|
rtcp_handlers.homer->func(log_ctx, ##__VA_ARGS__); \ |
|
|
} while (0) |
|
|
} while (0) |
|
|
@ -423,7 +451,11 @@ static int __rtcp_parse(GQueue *q, const str *_s, struct stream_fd *sfd, const e |
|
|
int min_packet_size; |
|
|
int min_packet_size; |
|
|
|
|
|
|
|
|
ZERO(log_ctx_s); |
|
|
ZERO(log_ctx_s); |
|
|
|
|
|
log_ctx_s.call = c; |
|
|
|
|
|
log_ctx_s.received = tv; |
|
|
|
|
|
|
|
|
log_ctx = &log_ctx_s; |
|
|
log_ctx = &log_ctx_s; |
|
|
|
|
|
|
|
|
CAH(init); |
|
|
CAH(init); |
|
|
CAH(start, c); |
|
|
CAH(start, c); |
|
|
|
|
|
|
|
|
@ -675,25 +707,52 @@ static void dummy_handler() { |
|
|
return; |
|
|
return; |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void scratch_common(struct rtcp_process_ctx *ctx, const struct rtcp_packet *common) { |
|
|
|
|
|
ctx->scratch_common_ssrc = htonl(common->ssrc); |
|
|
|
|
|
} |
|
|
static void scratch_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { |
|
|
static void scratch_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { |
|
|
ctx->scratch = (rr->number_lost[0] << 16) | (rr->number_lost[1] << 8) | rr->number_lost[2]; |
|
|
|
|
|
|
|
|
ctx->scratch.rr = (struct ssrc_receiver_report) { |
|
|
|
|
|
.from = ctx->scratch_common_ssrc, |
|
|
|
|
|
.ssrc = htonl(rr->ssrc), |
|
|
|
|
|
.high_seq_received = ntohl(rr->high_seq_received), |
|
|
|
|
|
.fraction_lost = rr->fraction_lost, |
|
|
|
|
|
.jitter = ntohl(rr->jitter), |
|
|
|
|
|
.lsr = ntohl(rr->lsr), |
|
|
|
|
|
.dlsr = ntohl(rr->dlsr), |
|
|
|
|
|
}; |
|
|
|
|
|
ctx->scratch.rr.packets_lost = (rr->number_lost[0] << 16) | (rr->number_lost[1] << 8) | rr->number_lost[2]; |
|
|
|
|
|
} |
|
|
|
|
|
static void scratch_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
|
|
|
ctx->scratch.sr = (struct ssrc_sender_report) { |
|
|
|
|
|
.ssrc = ctx->scratch_common_ssrc, |
|
|
|
|
|
.ntp_msw = ntohl(sr->ntp_msw), |
|
|
|
|
|
.ntp_lsw = ntohl(sr->ntp_lsw), |
|
|
|
|
|
.octet_count = ntohl(sr->octet_count), |
|
|
|
|
|
.timestamp = ntohl(sr->timestamp), |
|
|
|
|
|
.packet_count = ntohl(sr->packet_count), |
|
|
|
|
|
}; |
|
|
|
|
|
ctx->scratch.sr.ntp_ts = ntp_ts_to_double(ctx->scratch.sr.ntp_msw, ctx->scratch.sr.ntp_lsw); |
|
|
} |
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void homer_init(struct rtcp_process_ctx *ctx) { |
|
|
static void homer_init(struct rtcp_process_ctx *ctx) { |
|
|
ctx->json = g_string_new("{ "); |
|
|
ctx->json = g_string_new("{ "); |
|
|
} |
|
|
} |
|
|
static void homer_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
static void homer_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
g_string_append_printf(ctx->json, "\"sender_information\":{\"ntp_timestamp_sec\":%u," |
|
|
g_string_append_printf(ctx->json, "\"sender_information\":{\"ntp_timestamp_sec\":%u," |
|
|
"\"ntp_timestamp_usec\":%u,\"octets\":%u,\"rtp_timestamp\":%u, \"packets\":%u},", |
|
|
"\"ntp_timestamp_usec\":%u,\"octets\":%u,\"rtp_timestamp\":%u, \"packets\":%u},", |
|
|
ntohl(sr->ntp_msw), |
|
|
|
|
|
ntohl(sr->ntp_lsw), |
|
|
|
|
|
ntohl(sr->octet_count), |
|
|
|
|
|
ntohl(sr->timestamp), |
|
|
|
|
|
ntohl(sr->packet_count)); |
|
|
|
|
|
|
|
|
ctx->scratch.sr.ntp_msw, |
|
|
|
|
|
ctx->scratch.sr.ntp_lsw, |
|
|
|
|
|
ctx->scratch.sr.octet_count, |
|
|
|
|
|
ctx->scratch.sr.timestamp, |
|
|
|
|
|
ctx->scratch.sr.packet_count); |
|
|
} |
|
|
} |
|
|
static void homer_rr_list_start(struct rtcp_process_ctx *ctx, const struct rtcp_packet *common) { |
|
|
static void homer_rr_list_start(struct rtcp_process_ctx *ctx, const struct rtcp_packet *common) { |
|
|
g_string_append_printf(ctx->json, "\"ssrc\":%u,\"type\":%u,\"report_count\":%u,\"report_blocks\":[", |
|
|
g_string_append_printf(ctx->json, "\"ssrc\":%u,\"type\":%u,\"report_count\":%u,\"report_blocks\":[", |
|
|
ntohl(common->ssrc), |
|
|
|
|
|
|
|
|
ctx->scratch_common_ssrc, |
|
|
common->header.pt, |
|
|
common->header.pt, |
|
|
common->header.count); |
|
|
common->header.count); |
|
|
} |
|
|
} |
|
|
@ -701,13 +760,13 @@ static void homer_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr |
|
|
g_string_append_printf(ctx->json, "{\"source_ssrc\":%u," |
|
|
g_string_append_printf(ctx->json, "{\"source_ssrc\":%u," |
|
|
"\"highest_seq_no\":%u,\"fraction_lost\":%u,\"ia_jitter\":%u," |
|
|
"\"highest_seq_no\":%u,\"fraction_lost\":%u,\"ia_jitter\":%u," |
|
|
"\"packets_lost\":%u,\"lsr\":%u,\"dlsr\":%u},", |
|
|
"\"packets_lost\":%u,\"lsr\":%u,\"dlsr\":%u},", |
|
|
ntohl(rr->ssrc), |
|
|
|
|
|
ntohl(rr->high_seq_received), |
|
|
|
|
|
rr->fraction_lost, |
|
|
|
|
|
ntohl(rr->jitter), |
|
|
|
|
|
ctx->scratch, |
|
|
|
|
|
ntohl(rr->lsr), |
|
|
|
|
|
ntohl(rr->dlsr)); |
|
|
|
|
|
|
|
|
ctx->scratch.rr.ssrc, |
|
|
|
|
|
ctx->scratch.rr.high_seq_received, |
|
|
|
|
|
ctx->scratch.rr.fraction_lost, |
|
|
|
|
|
ctx->scratch.rr.jitter, |
|
|
|
|
|
ctx->scratch.rr.packets_lost, |
|
|
|
|
|
ctx->scratch.rr.lsr, |
|
|
|
|
|
ctx->scratch.rr.dlsr); |
|
|
} |
|
|
} |
|
|
static void homer_rr_list_end(struct rtcp_process_ctx *ctx) { |
|
|
static void homer_rr_list_end(struct rtcp_process_ctx *ctx) { |
|
|
str_sanitize(ctx->json); |
|
|
str_sanitize(ctx->json); |
|
|
@ -783,7 +842,7 @@ static void logging_common(struct rtcp_process_ctx *ctx, const struct rtcp_packe |
|
|
common->header.count, |
|
|
common->header.count, |
|
|
common->header.pt, |
|
|
common->header.pt, |
|
|
ntohs(common->header.length), |
|
|
ntohs(common->header.length), |
|
|
ntohl(common->ssrc)); |
|
|
|
|
|
|
|
|
ctx->scratch_common_ssrc); |
|
|
} |
|
|
} |
|
|
static void logging_sdes_list_start(struct rtcp_process_ctx *ctx, const struct source_description_packet *sdes) { |
|
|
static void logging_sdes_list_start(struct rtcp_process_ctx *ctx, const struct source_description_packet *sdes) { |
|
|
g_string_append_printf(ctx->log,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ", |
|
|
g_string_append_printf(ctx->log,"version=%u, padding=%u, count=%u, payloadtype=%u, length=%u, ", |
|
|
@ -794,22 +853,23 @@ static void logging_sdes_list_start(struct rtcp_process_ctx *ctx, const struct s |
|
|
ntohs(sdes->header.length)); |
|
|
ntohs(sdes->header.length)); |
|
|
} |
|
|
} |
|
|
static void logging_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
static void logging_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
g_string_append_printf(ctx->log,"ntp_sec=%u, ntp_fractions=%u, rtp_ts=%u, sender_packets=%u, sender_bytes=%u, ", |
|
|
|
|
|
ntohl(sr->ntp_msw), |
|
|
|
|
|
ntohl(sr->ntp_lsw), |
|
|
|
|
|
ntohl(sr->timestamp), |
|
|
|
|
|
ntohl(sr->packet_count), |
|
|
|
|
|
ntohl(sr->octet_count)); |
|
|
|
|
|
|
|
|
g_string_append_printf(ctx->log,"ntp_sec=%u, ntp_fractions=%u, rtp_ts=%u, sender_packets=%u, " \ |
|
|
|
|
|
"sender_bytes=%u, ", |
|
|
|
|
|
ctx->scratch.sr.ntp_msw, |
|
|
|
|
|
ctx->scratch.sr.ntp_lsw, |
|
|
|
|
|
ctx->scratch.sr.timestamp, |
|
|
|
|
|
ctx->scratch.sr.packet_count, |
|
|
|
|
|
ctx->scratch.sr.octet_count); |
|
|
} |
|
|
} |
|
|
static void logging_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { |
|
|
static void logging_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { |
|
|
g_string_append_printf(ctx->log,"ssrc=%u, fraction_lost=%u, packet_loss=%u, last_seq=%u, jitter=%u, last_sr=%u, delay_since_last_sr=%u, ", |
|
|
g_string_append_printf(ctx->log,"ssrc=%u, fraction_lost=%u, packet_loss=%u, last_seq=%u, jitter=%u, last_sr=%u, delay_since_last_sr=%u, ", |
|
|
ntohl(rr->ssrc), |
|
|
|
|
|
|
|
|
ctx->scratch.rr.ssrc, |
|
|
rr->fraction_lost, |
|
|
rr->fraction_lost, |
|
|
ctx->scratch, |
|
|
|
|
|
ntohl(rr->high_seq_received), |
|
|
|
|
|
ntohl(rr->jitter), |
|
|
|
|
|
ntohl(rr->lsr), |
|
|
|
|
|
ntohl(rr->dlsr)); |
|
|
|
|
|
|
|
|
ctx->scratch.rr.packets_lost, |
|
|
|
|
|
ctx->scratch.rr.high_seq_received, |
|
|
|
|
|
ctx->scratch.rr.jitter, |
|
|
|
|
|
ctx->scratch.rr.lsr, |
|
|
|
|
|
ctx->scratch.rr.dlsr); |
|
|
} |
|
|
} |
|
|
static void logging_xr(struct rtcp_process_ctx *ctx, const struct rtcp_packet *common, str *comp_s) { |
|
|
static void logging_xr(struct rtcp_process_ctx *ctx, const struct rtcp_packet *common, str *comp_s) { |
|
|
pjmedia_rtcp_xr_rx_rtcp_xr(ctx->log, common, comp_s); |
|
|
pjmedia_rtcp_xr_rx_rtcp_xr(ctx->log, common, comp_s); |
|
|
@ -826,6 +886,17 @@ static void logging_destroy(struct rtcp_process_ctx *ctx) { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void mos_sr(struct rtcp_process_ctx *ctx, const struct sender_report_packet *sr) { |
|
|
|
|
|
ssrc_sender_report(ctx->call, &ctx->scratch.sr, ctx->received); |
|
|
|
|
|
} |
|
|
|
|
|
static void mos_rr(struct rtcp_process_ctx *ctx, const struct report_block *rr) { |
|
|
|
|
|
ssrc_receiver_report(ctx->call, &ctx->scratch.rr, ctx->received); |
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void rtcp_init() { |
|
|
void rtcp_init() { |
|
|
rtcp_handlers.logging = _log_facility_rtcp ? &log_handlers : &dummy_handlers; |
|
|
rtcp_handlers.logging = _log_facility_rtcp ? &log_handlers : &dummy_handlers; |
|
|
rtcp_handlers.homer = has_homer() ? &homer_handlers : &dummy_handlers; |
|
|
rtcp_handlers.homer = has_homer() ? &homer_handlers : &dummy_handlers; |
|
|
|