#include "ssrc.h" #include #include "aux.h" #include "call.h" static struct ssrc_entry *create_ssrc_entry(u_int32_t ssrc) { struct ssrc_entry *ent; ent = g_slice_alloc0(sizeof(struct ssrc_entry)); ent->ssrc = ssrc; mutex_init(&ent->lock); return ent; } static void add_ssrc_entry(struct ssrc_entry *ent, struct ssrc_hash *ht) { g_hash_table_replace(ht->ht, &ent->ssrc, ent); } static void free_sender_report(void *p) { struct ssrc_sender_report_item *i = p; g_slice_free1(sizeof(*i), i); } static void free_ssrc_entry(void *p) { struct ssrc_entry *e = p; g_queue_clear_full(&e->sender_reports, free_sender_report); g_slice_free1(sizeof(*e), e); } struct ssrc_entry *find_ssrc(u_int32_t ssrc, struct ssrc_hash *ht) { rwlock_lock_r(&ht->lock); struct ssrc_entry *ret = g_hash_table_lookup(ht->ht, &ssrc); rwlock_unlock_r(&ht->lock); return ret; } struct ssrc_entry *get_ssrc(u_int32_t ssrc, struct ssrc_hash *ht /* , int *created */) { struct ssrc_entry *ent; restart: ent = find_ssrc(ssrc, ht); if (G_LIKELY(ent)) { // if (created) // *created = 0; return ent; } ent = create_ssrc_entry(ssrc); rwlock_lock_w(&ht->lock); if (g_hash_table_lookup(ht->ht, &ssrc)) { // preempted rwlock_unlock_w(&ht->lock); free_ssrc_entry(ent); goto restart; } add_ssrc_entry(ent, ht); rwlock_unlock_w(&ht->lock); // if (created) // *created = 1; return ent; } void free_ssrc_hash(struct ssrc_hash **ht) { if (!*ht) return; g_hash_table_destroy((*ht)->ht); g_slice_free1(sizeof(**ht), *ht); *ht = NULL; } struct ssrc_hash *create_ssrc_hash(void) { struct ssrc_hash *ret; ret = g_slice_alloc0(sizeof(*ret)); ret->ht = g_hash_table_new_full(uint32_hash, uint32_eq, NULL, free_ssrc_entry); rwlock_init(&ret->lock); return ret; } struct ssrc_ctx *get_ssrc_ctx(u_int32_t ssrc, struct ssrc_hash *ht, enum ssrc_dir dir) { struct ssrc_entry *s = get_ssrc(ssrc, ht /* , NULL */); return ((void *) s) + dir; } void ssrc_sender_report(struct call *c, const struct ssrc_sender_report *sr, const struct timeval *tv) { struct ssrc_entry *e; struct ssrc_sender_report_item *seri; seri = g_slice_alloc(sizeof(*seri)); seri->received = *tv; seri->report = *sr; seri->ntp_middle_bits = sr->ntp_msw << 16 | sr->ntp_lsw >> 16; ilog(LOG_DEBUG, "SR from %u: RTP TS %u PC %u OC %u NTP TS %u/%u=%f", sr->ssrc, sr->timestamp, sr->packet_count, sr->octet_count, sr->ntp_msw, sr->ntp_lsw, sr->ntp_ts); e = get_ssrc(sr->ssrc, c->ssrc_hash); mutex_lock(&e->lock); g_queue_push_tail(&e->sender_reports, seri); mutex_unlock(&e->lock); } void ssrc_receiver_report(struct call *c, const struct ssrc_receiver_report *rr, const struct timeval *tv) { ilog(LOG_DEBUG, "RR from %u about %u: FL %u TL %u HSR %u J %u LSR %u DLSR %u", rr->from, rr->ssrc, rr->fraction_lost, rr->packets_lost, rr->high_seq_received, rr->jitter, rr->lsr, rr->dlsr); if (!rr->lsr || !rr->dlsr) return; // no delay to be known struct ssrc_entry *e = get_ssrc(rr->ssrc, c->ssrc_hash); mutex_lock(&e->lock); // go through the list backwards until we find the SR referenced, up to 10 steps int i = 0; for (GList *l = e->sender_reports.tail; l && i < 10; l = l->prev, i++) { struct ssrc_sender_report_item *seri = l->data; if (seri->ntp_middle_bits != rr->lsr) continue; ilog(LOG_DEBUG, "RR from %u reports delay %u from %u", rr->from, rr->dlsr, rr->ssrc); break; } mutex_unlock(&e->lock); }