diff --git a/daemon/.ycm_extra_conf.py b/daemon/.ycm_extra_conf.py index aefe9b1ba..98d85353b 100644 --- a/daemon/.ycm_extra_conf.py +++ b/daemon/.ycm_extra_conf.py @@ -18,6 +18,7 @@ flags = [ '-fno-strict-aliasing', '-I/usr/include/glib-2.0', '-I/usr/lib/x86_64-linux-gnu/glib-2.0/include', + '-I/usr/include/json-glib-1.0', '-pthread', '-I../kernel-module/', '-I../lib/', diff --git a/daemon/call.c b/daemon/call.c index cf71f11c7..45750034a 100644 --- a/daemon/call.c +++ b/daemon/call.c @@ -594,7 +594,7 @@ static void call_timer(void *ptr) { if (sink) { mutex_lock(&sink->out_lock); if (sink->crypto.params.crypto_suite && sink->ssrc_out - && ke->target.ssrc == sink->ssrc_out->parent->ssrc + && ke->target.ssrc == sink->ssrc_out->parent->h.ssrc && ke->target.encrypt.last_index - sink->ssrc_out->srtp_index > 0x4000) { sink->ssrc_out->srtp_index = ke->target.encrypt.last_index; @@ -605,7 +605,7 @@ static void call_timer(void *ptr) { mutex_lock(&ps->in_lock); if (sfd->crypto.params.crypto_suite && ps->ssrc_in - && ke->target.ssrc == ps->ssrc_in->parent->ssrc + && ke->target.ssrc == ps->ssrc_in->parent->h.ssrc && ke->target.decrypt.last_index - ps->ssrc_in->srtp_index > 0x4000) { ps->ssrc_in->srtp_index = ke->target.decrypt.last_index; @@ -652,8 +652,8 @@ int call_init() { -void __payload_type_free(void *p) { - g_slice_free1(sizeof(struct rtp_payload_type), p); +void payload_type_free(struct rtp_payload_type *p) { + g_slice_free1(sizeof(*p), p); } static struct call_media *__get_media(struct call_monologue *ml, GList **it, const struct stream_params *sp) { @@ -683,7 +683,7 @@ static struct call_media *__get_media(struct call_monologue *ml, GList **it, con med->call = ml->call; med->index = sp->index; call_str_cpy(ml->call, &med->type, &sp->type); - med->codecs = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, __payload_type_free); + med->codecs = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, (GDestroyNotify) payload_type_free); med->codec_names = g_hash_table_new_full(str_hash, str_equal, NULL, (void (*)(void*)) g_queue_free); g_queue_push_tail(&ml->medias, med); @@ -1853,7 +1853,7 @@ void call_destroy(struct call *c) { (unsigned int) (ps->selected_sfd ? ps->selected_sfd->socket.local.port : 0), addr, ps->endpoint.port, (!PS_ISSET(ps, RTP) && PS_ISSET(ps, RTCP)) ? " (RTCP)" : "", - ps->ssrc_in ? ps->ssrc_in->parent->ssrc : 0, + ps->ssrc_in ? ps->ssrc_in->parent->h.ssrc : 0, atomic64_get(&ps->stats.packets), atomic64_get(&ps->stats.bytes), atomic64_get(&ps->stats.errors), @@ -1869,12 +1869,12 @@ void call_destroy(struct call *c) { k = g_hash_table_get_values(c->ssrc_hash->ht); for (l = k; l; l = l->next) { - struct ssrc_entry *se = l->data; + struct ssrc_entry_call *se = l->data; if (!se->stats_blocks.length || !se->lowest_mos || !se->highest_mos) continue; - ilog(LOG_INFO, "--- SSRC %" PRIu32 "", se->ssrc); + ilog(LOG_INFO, "--- SSRC %" PRIu32 "", se->h.ssrc); ilog(LOG_INFO, "------ Average MOS %" PRIu64 ".%" PRIu64 ", " "lowest MOS %" PRIu64 ".%" PRIu64 " (at %u:%02u), " "highest MOS %" PRIu64 ".%" PRIu64 " (at %u:%02u)", @@ -1986,7 +1986,7 @@ static void __call_free(void *p) { g_hash_table_destroy(md->codecs); g_hash_table_destroy(md->codec_names); g_queue_clear(&md->codecs_prefs_recv); - g_queue_clear_full(&md->codecs_prefs_send, __payload_type_free); + g_queue_clear_full(&md->codecs_prefs_send, (GDestroyNotify) payload_type_free); codec_handlers_free(md); g_slice_free1(sizeof(*md), md); } @@ -2027,7 +2027,7 @@ static struct call *call_create(const str *callid) { c->created = rtpe_now; c->dtls_cert = dtls_cert(); c->tos = rtpe_config.default_tos; - c->ssrc_hash = create_ssrc_hash(); + c->ssrc_hash = create_ssrc_hash_call(); return c; } diff --git a/daemon/call.h b/daemon/call.h index 1a5c778a8..b4f6a43a8 100644 --- a/daemon/call.h +++ b/daemon/call.h @@ -201,6 +201,7 @@ struct call_monologue; struct ice_agent; struct ssrc_hash; struct codec_handler; +struct rtp_payload_type; typedef bencode_buffer_t call_buffer_t; @@ -426,7 +427,7 @@ int call_stream_address46(char *o, struct packet_stream *ps, enum stream_address const struct transport_protocol *transport_protocol(const str *s); void add_total_calls_duration_in_interval(struct timeval *interval_tv); -void __payload_type_free(void *p); +void payload_type_free(struct rtp_payload_type *p); void __rtp_stats_update(GHashTable *dst, GHashTable *src); const struct rtp_payload_type *__rtp_stats_codec(struct call_media *m); diff --git a/daemon/call_interfaces.c b/daemon/call_interfaces.c index ef3789de0..aedbfae7a 100644 --- a/daemon/call_interfaces.c +++ b/daemon/call_interfaces.c @@ -989,7 +989,7 @@ static void ng_stats_stream(bencode_item_t *list, const struct packet_stream *ps BF_PS("ICE", ICE); if (ps->ssrc_in) - bencode_dictionary_add_integer(dict, "SSRC", ps->ssrc_in->parent->ssrc); + bencode_dictionary_add_integer(dict, "SSRC", ps->ssrc_in->parent->h.ssrc); stats: if (totals->last_packet < atomic64_get(&ps->last_packet)) @@ -1109,9 +1109,9 @@ static void ng_stats_ssrc(bencode_item_t *dict, struct ssrc_hash *ht) { GList *ll = g_hash_table_get_values(ht->ht); for (GList *l = ll; l; l = l->next) { - struct ssrc_entry *se = l->data; + struct ssrc_entry_call *se = l->data; char *tmp = bencode_buffer_alloc(dict->buffer, 12); - snprintf(tmp, 12, "%" PRIu32, se->ssrc); + snprintf(tmp, 12, "%" PRIu32, se->h.ssrc); bencode_item_t *ent = bencode_dictionary_add_dictionary(dict, tmp); if (!se->stats_blocks.length || !se->lowest_mos || !se->highest_mos) diff --git a/daemon/codec.c b/daemon/codec.c index c368260d5..25d01b566 100644 --- a/daemon/codec.c +++ b/daemon/codec.c @@ -210,7 +210,7 @@ static struct rtp_payload_type *codec_add_payload_type(const str *codec, struct ilog(LOG_WARN, "Ran out of RTP payload type numbers while adding codec '" STR_FORMAT "' for transcoding", STR_FMT(codec)); - __payload_type_free(pt); + payload_type_free(pt); return NULL; } } @@ -239,7 +239,7 @@ static struct rtp_payload_type *__rtp_payload_type_add_recv(struct call_media *m struct rtp_payload_type *existing_pt; if ((existing_pt = g_hash_table_lookup(media->codecs, &pt->payload_type))) { // collision/duplicate - ignore - __payload_type_free(pt); + payload_type_free(pt); return existing_pt; } g_hash_table_replace(media->codecs, &pt->payload_type, pt); @@ -275,7 +275,7 @@ static void __rtp_payload_type_add(struct call_media *media, struct call_media * static void __payload_queue_free(void *qq) { GQueue *q = qq; - g_queue_free_full(q, __payload_type_free); + g_queue_free_full(q, (GDestroyNotify) payload_type_free); } static int __revert_codec_strip(GHashTable *removed, const str *codec, struct call_media *media, struct call_media *other_media) { @@ -305,7 +305,7 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ // start fresh g_queue_clear(&media->codecs_prefs_recv); - g_queue_clear_full(&other_media->codecs_prefs_send, __payload_type_free); + g_queue_clear_full(&other_media->codecs_prefs_send, (GDestroyNotify) payload_type_free); g_hash_table_remove_all(media->codecs); g_hash_table_remove_all(media->codec_names); diff --git a/daemon/media_socket.c b/daemon/media_socket.c index 02b7580dd..3303b4d42 100644 --- a/daemon/media_socket.c +++ b/daemon/media_socket.c @@ -1028,7 +1028,7 @@ void kernelize(struct packet_stream *stream) { __re_address_translate_ep(&reti.dst_addr, &sink->endpoint); __re_address_translate_ep(&reti.src_addr, &sink->selected_sfd->socket.local); - reti.ssrc = stream->ssrc_in ? htonl(stream->ssrc_in->parent->ssrc) : 0; + reti.ssrc = stream->ssrc_in ? htonl(stream->ssrc_in->parent->h.ssrc) : 0; stream->handler->in->kernel(&reti.decrypt, stream); stream->handler->out->kernel(&reti.encrypt, sink); @@ -1171,7 +1171,7 @@ static void __stream_ssrc(struct packet_stream *in_srtp, struct packet_stream *o mutex_lock(&in_srtp->in_lock); (*ssrc_in_p) = in_srtp->ssrc_in; - if (G_UNLIKELY(!(*ssrc_in_p) || (*ssrc_in_p)->parent->ssrc != ssrc)) { + if (G_UNLIKELY(!(*ssrc_in_p) || (*ssrc_in_p)->parent->h.ssrc != ssrc)) { // SSRC mismatch - get the new entry (*ssrc_in_p) = in_srtp->ssrc_in = get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_INPUT); @@ -1183,7 +1183,7 @@ static void __stream_ssrc(struct packet_stream *in_srtp, struct packet_stream *o mutex_lock(&out_srtp->out_lock); (*ssrc_out_p) = out_srtp->ssrc_out; - if (G_UNLIKELY(!(*ssrc_out_p) || (*ssrc_out_p)->parent->ssrc != ssrc)) { + if (G_UNLIKELY(!(*ssrc_out_p) || (*ssrc_out_p)->parent->h.ssrc != ssrc)) { // SSRC mismatch - get the new entry (*ssrc_out_p) = out_srtp->ssrc_out = get_ssrc_ctx(ssrc, ssrc_hash, SSRC_DIR_OUTPUT); diff --git a/daemon/redis.c b/daemon/redis.c index 5c9de8608..fc2a907bb 100644 --- a/daemon/redis.c +++ b/daemon/redis.c @@ -1243,7 +1243,7 @@ static int json_medias(struct call *c, struct redis_list *medias, JsonReader *ro med = uid_slice_alloc0(med, &c->medias); med->call = c; med->codecs = g_hash_table_new_full(g_int_hash, g_int_equal, NULL, - __payload_type_free); + (GDestroyNotify) payload_type_free); if (redis_hash_get_unsigned(&med->index, rh, "index")) return -1; @@ -1467,7 +1467,7 @@ static int json_build_ssrc(struct call *c, JsonReader *root_reader) { return -1; u_int32_t ssrc = json_reader_get_ll(root_reader, "ssrc"); - struct ssrc_entry *se = get_ssrc(ssrc, c->ssrc_hash); + struct ssrc_entry_call *se = get_ssrc(ssrc, c->ssrc_hash); se->input_ctx.srtp_index = json_reader_get_ll(root_reader, "in_srtp_index"); se->input_ctx.srtcp_index = json_reader_get_ll(root_reader, "in_srtcp_index"); se->output_ctx.srtp_index = json_reader_get_ll(root_reader, "out_srtp_index"); @@ -2068,10 +2068,10 @@ char* redis_encode_json(struct call *c) { json_builder_set_member_name(builder, "ssrc_table"); json_builder_begin_array (builder); for (m = k; m; m = m->next) { - struct ssrc_entry *se = m->data; + struct ssrc_entry_call *se = m->data; json_builder_begin_object (builder); - JSON_SET_SIMPLE("ssrc","%" PRIu32, se->ssrc); + JSON_SET_SIMPLE("ssrc","%" PRIu32, se->h.ssrc); // XXX use function for in/out JSON_SET_SIMPLE("in_srtp_index","%" PRIu64, se->input_ctx.srtp_index); JSON_SET_SIMPLE("in_srtcp_index","%" PRIu64, se->input_ctx.srtcp_index); diff --git a/daemon/ssrc.c b/daemon/ssrc.c index ba856350a..c63b25106 100644 --- a/daemon/ssrc.c +++ b/daemon/ssrc.c @@ -6,20 +6,23 @@ -static void init_ssrc_ctx(struct ssrc_ctx *c, struct ssrc_entry *parent) { +static void init_ssrc_ctx(struct ssrc_ctx *c, struct ssrc_entry_call *parent) { c->parent = parent; } -static struct ssrc_entry *create_ssrc_entry(u_int32_t ssrc) { - struct ssrc_entry *ent; - ent = g_slice_alloc0(sizeof(struct ssrc_entry)); +static void init_ssrc_entry(struct ssrc_entry *ent, u_int32_t ssrc) { ent->ssrc = ssrc; mutex_init(&ent->lock); +} +static struct ssrc_entry *create_ssrc_entry_call(void *uptr) { + struct ssrc_entry_call *ent; + ent = g_slice_alloc0(sizeof(*ent)); ent->payload_type = -1; init_ssrc_ctx(&ent->input_ctx, ent); init_ssrc_ctx(&ent->output_ctx, ent); - return ent; + return &ent->h; } -static void add_ssrc_entry(struct ssrc_entry *ent, struct ssrc_hash *ht) { +static void add_ssrc_entry(u_int32_t ssrc, struct ssrc_entry *ent, struct ssrc_hash *ht) { + init_ssrc_entry(ent, ssrc); g_hash_table_replace(ht->ht, &ent->ssrc, ent); g_queue_push_tail(&ht->q, ent); } @@ -32,7 +35,7 @@ static void free_rr_time(struct ssrc_rr_time_item *i) { static void free_stats_block(struct ssrc_stats_block *ssb) { g_slice_free1(sizeof(*ssb), ssb); } -static void free_ssrc_entry(struct ssrc_entry *e) { +static void free_ssrc_entry_call(struct ssrc_entry_call *e) { g_queue_clear_full(&e->sender_reports, (GDestroyNotify) free_sender_report); g_queue_clear_full(&e->rr_time_reports, (GDestroyNotify) free_rr_time); g_queue_clear_full(&e->stats_blocks, (GDestroyNotify) free_stats_block); @@ -58,13 +61,18 @@ static void mos_calc(struct ssrc_stats_block *ssb) { ssb->mos = intmos; } -struct ssrc_entry *find_ssrc(u_int32_t ssrc, struct ssrc_hash *ht) { +static 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); + struct ssrc_entry *ret = g_atomic_pointer_get(&ht->cache); + if (!ret || ret->ssrc != ssrc) { + ret = g_hash_table_lookup(ht->ht, &ssrc); + if (ret) + g_atomic_pointer_set(&ht->cache, ret); + } rwlock_unlock_r(&ht->lock); return ret; } -struct ssrc_entry *get_ssrc(u_int32_t ssrc, struct ssrc_hash *ht /* , int *created */) { +void *get_ssrc(u_int32_t ssrc, struct ssrc_hash *ht /* , int *created */) { struct ssrc_entry *ent; restart: @@ -75,7 +83,19 @@ restart: return ent; } - ent = create_ssrc_entry(ssrc); + // use precreated entry if possible + while (1) { + ent = g_atomic_pointer_get(&ht->precreat); + if (!ent) + break; // create one ourselves + if (g_atomic_pointer_compare_and_exchange(&ht->precreat, ent, NULL)) + break; + // something got in the way - retry + } + if (G_UNLIKELY(!ent)) + ent = ht->create_func(ht->uptr); + if (G_UNLIKELY(!ent)) + return NULL; rwlock_lock_w(&ht->lock); @@ -84,18 +104,30 @@ restart: ilog(LOG_DEBUG, "SSRC hash table exceeded size limit (trying to add %u) - deleting SSRC %u", ssrc, old_ent->ssrc); g_hash_table_remove(ht->ht, &old_ent->ssrc); + g_atomic_pointer_set(&ht->cache, NULL); } if (g_hash_table_lookup(ht->ht, &ssrc)) { // preempted rwlock_unlock_w(&ht->lock); - free_ssrc_entry(ent); + // return created entry if slot is still empty + if (!g_atomic_pointer_compare_and_exchange(&ht->precreat, NULL, ent)) + ht->destroy_func(ent); goto restart; } - add_ssrc_entry(ent, ht); + add_ssrc_entry(ssrc, ent, ht); + g_atomic_pointer_set(&ht->cache, ent); rwlock_unlock_w(&ht->lock); // if (created) // *created = 1; + + // keep entry filled for next SSRC + if (g_atomic_pointer_get(&ht->precreat) == NULL) { + struct ssrc_entry *nextent = ht->create_func(ht->uptr); + if (!g_atomic_pointer_compare_and_exchange(&ht->precreat, NULL, nextent)) + ht->destroy_func(nextent); + } + return ent; } void free_ssrc_hash(struct ssrc_hash **ht) { @@ -103,18 +135,27 @@ void free_ssrc_hash(struct ssrc_hash **ht) { return; g_hash_table_destroy((*ht)->ht); g_queue_clear(&(*ht)->q); + if ((*ht)->precreat) + (*ht)->destroy_func((void *) (*ht)->precreat); g_slice_free1(sizeof(**ht), *ht); *ht = NULL; } -struct ssrc_hash *create_ssrc_hash(void) { +struct ssrc_hash *create_ssrc_hash_full(ssrc_create_func_t cfunc, ssrc_free_func_t ffunc, void *uptr) { struct ssrc_hash *ret; ret = g_slice_alloc0(sizeof(*ret)); - ret->ht = g_hash_table_new_full(uint32_hash, uint32_eq, NULL, (GDestroyNotify) free_ssrc_entry); + ret->ht = g_hash_table_new_full(uint32_hash, uint32_eq, NULL, (GDestroyNotify) ffunc); rwlock_init(&ret->lock); + ret->create_func = cfunc; + ret->destroy_func = ffunc; + ret->uptr = uptr; + ret->precreat = cfunc(uptr); // because object creation might be slow return ret; } +struct ssrc_hash *create_ssrc_hash_call(void) { + return create_ssrc_hash_full(create_ssrc_entry_call, (ssrc_free_func_t) free_ssrc_entry_call, NULL); +} 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 */); @@ -165,7 +206,7 @@ static long long __calc_rtt(struct call *c, u_int32_t ssrc, u_int32_t ntp_middle if (!ntp_middle_bits || !delay) return 0; - struct ssrc_entry *e = get_ssrc(ssrc, c->ssrc_hash); + struct ssrc_entry_call *e = get_ssrc(ssrc, c->ssrc_hash); if (G_UNLIKELY(!e)) return 0; @@ -174,7 +215,7 @@ static long long __calc_rtt(struct call *c, u_int32_t ssrc, u_int32_t ntp_middle struct ssrc_time_item *sti; GQueue *q = (((void *) e) + reports_queue_offset); - mutex_lock(&e->lock); + mutex_lock(&e->h.lock); // go through the list backwards until we find the SR referenced for (GList *l = q->tail; l; l = l->prev) { sti = l->data; @@ -184,14 +225,14 @@ static long long __calc_rtt(struct call *c, u_int32_t ssrc, u_int32_t ntp_middle } // not found - mutex_unlock(&e->lock); + mutex_unlock(&e->h.lock); return 0; found:; // `e` remains locked for access to `sti` long long rtt = timeval_diff(tv, &sti->received); - mutex_unlock(&e->lock); + mutex_unlock(&e->h.lock); rtt -= (long long) delay * 1000000LL / 65536LL; ilog(LOG_DEBUG, "Calculated round-trip time for %u is %lli us", ssrc, rtt); @@ -211,7 +252,7 @@ void ssrc_sender_report(struct call_media *m, const struct ssrc_sender_report *s { struct ssrc_entry *e; struct ssrc_sender_report_item *seri = __do_time_report_item(m, sizeof(*seri), - G_STRUCT_OFFSET(struct ssrc_entry, sender_reports), tv, sr->ssrc, + G_STRUCT_OFFSET(struct ssrc_entry_call, sender_reports), tv, sr->ssrc, sr->ntp_msw, sr->ntp_lsw, (GDestroyNotify) free_sender_report, &e); if (!seri) return; @@ -236,9 +277,9 @@ void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_repor int pt; long long rtt = __calc_rtt(c, rr->ssrc, rr->lsr, rr->dlsr, - G_STRUCT_OFFSET(struct ssrc_entry, sender_reports), tv, &pt); + G_STRUCT_OFFSET(struct ssrc_entry_call, sender_reports), tv, &pt); - struct ssrc_entry *other_e = get_ssrc(rr->from, c->ssrc_hash); + struct ssrc_entry_call *other_e = get_ssrc(rr->from, c->ssrc_hash); if (G_UNLIKELY(!other_e)) goto out_nl; @@ -273,7 +314,7 @@ void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_repor ilog(LOG_DEBUG, "Calculated MOS from RR for %u is %.1f", rr->from, (double) ssb->mos / 10.0); // got a new stats block, add it to reporting ssrc - mutex_lock(&other_e->lock); + mutex_lock(&other_e->h.lock); // discard stats block if last has been received less than a second ago if (G_LIKELY(other_e->stats_blocks.length > 0)) { @@ -300,7 +341,7 @@ void ssrc_receiver_report(struct call_media *m, const struct ssrc_receiver_repor goto out_ul_oe; out_ul_oe: - mutex_unlock(&other_e->lock); + mutex_unlock(&other_e->h.lock); goto out_nl; out_nl: ; @@ -311,7 +352,7 @@ void ssrc_receiver_rr_time(struct call_media *m, const struct ssrc_xr_rr_time *r { struct ssrc_entry *e; struct ssrc_rr_time_item *srti = __do_time_report_item(m, sizeof(*srti), - G_STRUCT_OFFSET(struct ssrc_entry, rr_time_reports), tv, rr->ssrc, + G_STRUCT_OFFSET(struct ssrc_entry_call, rr_time_reports), tv, rr->ssrc, rr->ntp_msw, rr->ntp_lsw, (GDestroyNotify) free_rr_time, &e); if (!srti) return; @@ -331,7 +372,7 @@ void ssrc_receiver_dlrr(struct call_media *m, const struct ssrc_xr_dlrr *dlrr, dlrr->lrr, dlrr->dlrr); __calc_rtt(m->call, dlrr->ssrc, dlrr->lrr, dlrr->dlrr, - G_STRUCT_OFFSET(struct ssrc_entry, rr_time_reports), tv, NULL); + G_STRUCT_OFFSET(struct ssrc_entry_call, rr_time_reports), tv, NULL); } void ssrc_voip_metrics(struct call_media *m, const struct ssrc_xr_voip_metrics *vm, @@ -348,7 +389,7 @@ void ssrc_voip_metrics(struct call_media *m, const struct ssrc_xr_voip_metrics * vm->jb_max, vm->jb_abs_max); struct call *c = m->call; - struct ssrc_entry *e = get_ssrc(vm->ssrc, c->ssrc_hash); + struct ssrc_entry_call *e = get_ssrc(vm->ssrc, c->ssrc_hash); if (!e) return; e->last_rtt = vm->rnd_trip_delay; diff --git a/daemon/ssrc.h b/daemon/ssrc.h index 0d261542f..26111c9c6 100644 --- a/daemon/ssrc.h +++ b/daemon/ssrc.h @@ -15,17 +15,27 @@ struct call_media; struct timeval; struct rtp_payload_type; struct ssrc_entry; +struct ssrc_entry_call; enum ssrc_dir; +typedef struct ssrc_entry *(*ssrc_create_func_t)(void *uptr); +typedef void (*ssrc_free_func_t)(struct ssrc_entry *); + + struct ssrc_hash { GHashTable *ht; GQueue q; rwlock_t lock; + ssrc_create_func_t create_func; + void *uptr; + ssrc_free_func_t destroy_func; + volatile struct ssrc_entry *cache; // last used entry + volatile struct ssrc_entry *precreat; // next used entry }; struct ssrc_ctx { - struct ssrc_entry *parent; + struct ssrc_entry_call *parent; // XXX lock this? u_int64_t srtp_index, srtcp_index; @@ -43,6 +53,10 @@ struct ssrc_stats_block { struct ssrc_entry { mutex_t lock; u_int32_t ssrc; +}; + +struct ssrc_entry_call { + struct ssrc_entry h; // must be first struct ssrc_ctx input_ctx, output_ctx; GQueue sender_reports; // as received via RTCP @@ -55,8 +69,8 @@ struct ssrc_entry { unsigned int last_rtt; // last calculated raw rtt without rtt from opposide side }; enum ssrc_dir { // these values must not be used externally - SSRC_DIR_INPUT = G_STRUCT_OFFSET(struct ssrc_entry, input_ctx), - SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry, output_ctx), + SSRC_DIR_INPUT = G_STRUCT_OFFSET(struct ssrc_entry_call, input_ctx), + SSRC_DIR_OUTPUT = G_STRUCT_OFFSET(struct ssrc_entry_call, output_ctx), }; struct ssrc_time_item { @@ -137,11 +151,12 @@ struct ssrc_xr_voip_metrics { void free_ssrc_hash(struct ssrc_hash **); -struct ssrc_hash *create_ssrc_hash(void); +struct ssrc_hash *create_ssrc_hash_full(ssrc_create_func_t, ssrc_free_func_t, void *uptr); + +struct ssrc_hash *create_ssrc_hash_call(void); + +void *get_ssrc(u_int32_t, struct ssrc_hash * /* , int *created */); // creates new entry if not found -struct ssrc_entry *find_ssrc(u_int32_t, struct ssrc_hash *); // returns NULL if not found -struct ssrc_entry *get_ssrc(u_int32_t, struct ssrc_hash * /* , int *created */); // creates new entry if not found -//struct ssrc_entry *create_ssrc_entry(u_int32_t); struct ssrc_ctx *get_ssrc_ctx(u_int32_t, struct ssrc_hash *, enum ssrc_dir); // creates new entry if not found