|
|
|
@ -15,6 +15,7 @@
|
|
|
|
|
#include "media_socket.h"
|
|
|
|
|
#include "rtcplib.h"
|
|
|
|
|
#include "ssrc.h"
|
|
|
|
|
#include "sdp.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -1376,3 +1377,115 @@ void rtcp_init() {
|
|
|
|
|
rtcp_handlers.logging = _log_facility_rtcp ? &log_handlers : &dummy_handlers;
|
|
|
|
|
rtcp_handlers.homer = has_homer() ? &homer_handlers : &dummy_handlers;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GString *rtcp_sender_report(uint32_t ssrc, uint32_t ts, uint32_t packets, uint32_t octets, GQueue *rrs) {
|
|
|
|
|
GString *ret = g_string_sized_new(128);
|
|
|
|
|
g_string_set_size(ret, sizeof(struct sender_report_packet));
|
|
|
|
|
struct sender_report_packet *sr = (void *) ret->str;
|
|
|
|
|
|
|
|
|
|
*sr = (struct sender_report_packet) {
|
|
|
|
|
.rtcp.header.version = 2,
|
|
|
|
|
.rtcp.header.pt = RTCP_PT_SR,
|
|
|
|
|
.rtcp.ssrc = htonl(ssrc),
|
|
|
|
|
.ntp_msw = htonl(rtpe_now.tv_sec + 2208988800),
|
|
|
|
|
.ntp_lsw = htonl((4294967295ULL * rtpe_now.tv_usec) / 1000000ULL),
|
|
|
|
|
.timestamp = htonl(ts), // XXX calculate from rtpe_now instead
|
|
|
|
|
.packet_count = htonl(packets),
|
|
|
|
|
.octet_count = htonl(octets),
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// receiver reports
|
|
|
|
|
int i = 0, n = 0;
|
|
|
|
|
for (GList *l = rrs->head; l; l = l->next) {
|
|
|
|
|
struct ssrc_ctx *s = l->data;
|
|
|
|
|
if (i < 30) {
|
|
|
|
|
struct report_block *rr = (void *) ret->str + ret->len;
|
|
|
|
|
g_string_set_size(ret, ret->len + sizeof(*rr));
|
|
|
|
|
|
|
|
|
|
// XXX unify with transcode_rr
|
|
|
|
|
|
|
|
|
|
// last received SR?
|
|
|
|
|
struct ssrc_entry_call *se = s->parent;
|
|
|
|
|
long long tv_diff = 0;
|
|
|
|
|
uint32_t ntp_middle_bits = 0;
|
|
|
|
|
mutex_lock(&se->h.lock);
|
|
|
|
|
if (se->sender_reports.length) {
|
|
|
|
|
struct ssrc_time_item *si = se->sender_reports.tail->data;
|
|
|
|
|
tv_diff = timeval_diff(&rtpe_now, &si->received);
|
|
|
|
|
ntp_middle_bits = si->ntp_middle_bits;
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&se->h.lock);
|
|
|
|
|
|
|
|
|
|
uint64_t lost = atomic64_get(&s->packets_lost);
|
|
|
|
|
uint64_t tot = atomic64_get(&s->packets);
|
|
|
|
|
|
|
|
|
|
*rr = (struct report_block) {
|
|
|
|
|
.ssrc = htonl(s->parent->h.ssrc),
|
|
|
|
|
.fraction_lost = lost * 256 / (tot + lost),
|
|
|
|
|
.number_lost[0] = (lost >> 16) & 0xff,
|
|
|
|
|
.number_lost[1] = (lost >> 8) & 0xff,
|
|
|
|
|
.number_lost[2] = lost & 0xff,
|
|
|
|
|
.high_seq_received = htonl(atomic64_get(&s->last_seq)),
|
|
|
|
|
.lsr = htonl(ntp_middle_bits),
|
|
|
|
|
.dlsr = htonl(tv_diff * 65536 / 1000000),
|
|
|
|
|
};
|
|
|
|
|
// XXX jitter
|
|
|
|
|
n++;
|
|
|
|
|
}
|
|
|
|
|
ssrc_ctx_put(&s);
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sr->rtcp.header.count = n;
|
|
|
|
|
sr->rtcp.header.length = htons((ret->len >> 2) - 1);
|
|
|
|
|
|
|
|
|
|
// sdes
|
|
|
|
|
assert(rtpe_instance_id.len == 12);
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
struct source_description_packet sdes;
|
|
|
|
|
struct sdes_chunk chunk;
|
|
|
|
|
struct sdes_item cname;
|
|
|
|
|
char str[12];
|
|
|
|
|
char nul;
|
|
|
|
|
char pad;
|
|
|
|
|
} __attribute__ ((packed)) *sdes;
|
|
|
|
|
|
|
|
|
|
assert(sizeof(*sdes) == 24);
|
|
|
|
|
|
|
|
|
|
sdes = (void *) ret->str + ret->len;
|
|
|
|
|
g_string_set_size(ret, ret->len + sizeof(*sdes));
|
|
|
|
|
|
|
|
|
|
*sdes = (__typeof(*sdes)) {
|
|
|
|
|
.sdes.header.version = 2,
|
|
|
|
|
.sdes.header.pt = RTCP_PT_SDES,
|
|
|
|
|
.sdes.header.count = 1,
|
|
|
|
|
.sdes.header.length = htons((sizeof(*sdes) >> 2) - 1),
|
|
|
|
|
.chunk.ssrc = htonl(ssrc),
|
|
|
|
|
.cname.type = SDES_TYPE_CNAME,
|
|
|
|
|
.cname.length = rtpe_instance_id.len,
|
|
|
|
|
.nul = 0,
|
|
|
|
|
.pad = 0,
|
|
|
|
|
};
|
|
|
|
|
memcpy(sdes->str, rtpe_instance_id.s, rtpe_instance_id.len);
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void rtcp_receiver_reports(GQueue *out, struct ssrc_hash *hash, struct call_monologue *ml) {
|
|
|
|
|
rwlock_lock_r(&hash->lock);
|
|
|
|
|
for (GList *l = hash->q.head; l; l = l->next) {
|
|
|
|
|
struct ssrc_entry_call *e = l->data;
|
|
|
|
|
ilog(LOG_DEBUG, "xxxxx %x %i %i %p %p %p", e->h.ssrc, (int) atomic64_get(&e->input_ctx.packets), (int) atomic64_get(&e->output_ctx.packets), ml, e->input_ctx.ref, e->output_ctx.ref);
|
|
|
|
|
struct ssrc_ctx *i = &e->input_ctx;
|
|
|
|
|
if (i->ref != ml)
|
|
|
|
|
continue;
|
|
|
|
|
if (!atomic64_get(&i->packets))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
g_queue_push_tail(out, ssrc_ctx_get(i));
|
|
|
|
|
}
|
|
|
|
|
rwlock_unlock_r(&hash->lock);
|
|
|
|
|
}
|
|
|
|
|