|
|
|
|
@ -58,7 +58,7 @@ static void codec_store_add_raw_order(struct codec_store *cs, rtp_payload_type *
|
|
|
|
|
static rtp_payload_type *codec_store_find_compatible(struct codec_store *cs,
|
|
|
|
|
const rtp_payload_type *pt);
|
|
|
|
|
static void __rtp_payload_type_add_name(codec_names_ht, rtp_payload_type *pt);
|
|
|
|
|
static void codec_calc_lost(struct ssrc_ctx *ssrc, uint16_t seq);
|
|
|
|
|
static void codec_calc_lost(struct ssrc_entry_call *ssrc, uint16_t seq);
|
|
|
|
|
static void __codec_options_set(call_t *call, rtp_payload_type *pt, str_case_value_ht codec_set);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -422,7 +422,7 @@ static void __handler_shutdown(struct codec_handler *handler) {
|
|
|
|
|
delay_buffer_stop(&handler->delay_buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj_release(handler->ssrc_handler);
|
|
|
|
|
ssrc_entry_release(handler->ssrc_handler);
|
|
|
|
|
handler->kernelize = false;
|
|
|
|
|
handler->transcoder = false;
|
|
|
|
|
handler->output_handler = handler; // reset to default
|
|
|
|
|
@ -1315,7 +1315,7 @@ static void __rtcp_timer_run(struct codec_timer *ct) {
|
|
|
|
|
rwlock_lock_r(&rt->call->master_lock);
|
|
|
|
|
|
|
|
|
|
// copy out references to SSRCs for lock-free handling
|
|
|
|
|
struct ssrc_ctx *ssrc_out[RTPE_NUM_SSRC_TRACKING] = {NULL,};
|
|
|
|
|
struct ssrc_entry_call *ssrc_out[RTPE_NUM_SSRC_TRACKING] = {NULL,};
|
|
|
|
|
if (media->streams.head) {
|
|
|
|
|
struct packet_stream *ps = media->streams.head->data;
|
|
|
|
|
mutex_lock(&ps->out_lock);
|
|
|
|
|
@ -1323,7 +1323,7 @@ static void __rtcp_timer_run(struct codec_timer *ct) {
|
|
|
|
|
if (!ps->ssrc_out[u]) // end of list
|
|
|
|
|
break;
|
|
|
|
|
ssrc_out[u] = ps->ssrc_out[u];
|
|
|
|
|
ssrc_ctx_hold(ssrc_out[u]);
|
|
|
|
|
ssrc_entry_hold(ssrc_out[u]);
|
|
|
|
|
}
|
|
|
|
|
mutex_unlock(&ps->out_lock);
|
|
|
|
|
}
|
|
|
|
|
@ -1340,7 +1340,7 @@ static void __rtcp_timer_run(struct codec_timer *ct) {
|
|
|
|
|
for (unsigned int u = 0; u < RTPE_NUM_SSRC_TRACKING; u++) {
|
|
|
|
|
if (!ssrc_out[u]) // end of list
|
|
|
|
|
break;
|
|
|
|
|
ssrc_ctx_put(&ssrc_out[u]);
|
|
|
|
|
ssrc_entry_release(ssrc_out[u]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
@ -2011,7 +2011,7 @@ void mqtt_timer_start(struct mqtt_timer **mqtp, call_t *call, struct call_media
|
|
|
|
|
static void codec_timer_stop(struct codec_timer **ctp) {
|
|
|
|
|
if (!ctp)
|
|
|
|
|
return;
|
|
|
|
|
obj_release(*ctp);
|
|
|
|
|
obj_release_o(*ctp);
|
|
|
|
|
}
|
|
|
|
|
// master lock held in W
|
|
|
|
|
void rtcp_timer_stop(struct rtcp_timer **rtp) {
|
|
|
|
|
@ -2064,7 +2064,7 @@ static void codec_add_raw_packet_common(struct media_packet *mp, unsigned int cl
|
|
|
|
|
{
|
|
|
|
|
p->clockrate = clockrate;
|
|
|
|
|
if (mp->rtp && mp->ssrc_out) {
|
|
|
|
|
ssrc_ctx_hold(mp->ssrc_out);
|
|
|
|
|
ssrc_entry_hold(mp->ssrc_out);
|
|
|
|
|
p->ssrc_out = mp->ssrc_out;
|
|
|
|
|
if (!p->rtp)
|
|
|
|
|
p->rtp = mp->rtp;
|
|
|
|
|
@ -2139,36 +2139,19 @@ static int handler_func_passthrough(struct codec_handler *h, struct media_packet
|
|
|
|
|
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
static void __ssrc_lock_both(struct media_packet *mp) {
|
|
|
|
|
struct ssrc_ctx *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in_p = ssrc_in->parent;
|
|
|
|
|
struct ssrc_ctx *ssrc_out = mp->ssrc_out;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out_p = ssrc_out->parent;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out = mp->ssrc_out;
|
|
|
|
|
|
|
|
|
|
// we need a nested lock here - both input and output SSRC needs to be locked.
|
|
|
|
|
// we don't know the lock order, so try both, and keep trying until we succeed.
|
|
|
|
|
while (1) {
|
|
|
|
|
mutex_lock(&ssrc_in_p->h.lock);
|
|
|
|
|
if (ssrc_in_p == ssrc_out_p)
|
|
|
|
|
break;
|
|
|
|
|
if (!mutex_trylock(&ssrc_out_p->h.lock))
|
|
|
|
|
break;
|
|
|
|
|
mutex_unlock(&ssrc_in_p->h.lock);
|
|
|
|
|
|
|
|
|
|
mutex_lock(&ssrc_out_p->h.lock);
|
|
|
|
|
if (!mutex_trylock(&ssrc_in_p->h.lock))
|
|
|
|
|
break;
|
|
|
|
|
mutex_unlock(&ssrc_out_p->h.lock);
|
|
|
|
|
}
|
|
|
|
|
// nested lock: in first, out second
|
|
|
|
|
mutex_lock(&ssrc_in->h.lock);
|
|
|
|
|
mutex_lock(&ssrc_out->h.lock);
|
|
|
|
|
}
|
|
|
|
|
static void __ssrc_unlock_both(struct media_packet *mp) {
|
|
|
|
|
struct ssrc_ctx *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in_p = ssrc_in->parent;
|
|
|
|
|
struct ssrc_ctx *ssrc_out = mp->ssrc_out;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out_p = ssrc_out->parent;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out = mp->ssrc_out;
|
|
|
|
|
|
|
|
|
|
mutex_unlock(&ssrc_in_p->h.lock);
|
|
|
|
|
if (ssrc_in_p != ssrc_out_p)
|
|
|
|
|
mutex_unlock(&ssrc_out_p->h.lock);
|
|
|
|
|
mutex_unlock(&ssrc_in->h.lock);
|
|
|
|
|
mutex_unlock(&ssrc_out->h.lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __seq_free(void *p) {
|
|
|
|
|
@ -2181,12 +2164,10 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
{
|
|
|
|
|
struct codec_handler *h = packet->handler;
|
|
|
|
|
|
|
|
|
|
struct ssrc_ctx *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in_p = ssrc_in->parent;
|
|
|
|
|
struct ssrc_ctx *ssrc_out = mp->ssrc_out;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out_p = ssrc_out->parent;
|
|
|
|
|
struct ssrc_entry_call *ssrc_in = mp->ssrc_in;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out = mp->ssrc_out;
|
|
|
|
|
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(ssrc_in_p->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(ssrc_in->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
if (G_UNLIKELY(!ch)) {
|
|
|
|
|
__transcode_packet_free(packet);
|
|
|
|
|
return 0;
|
|
|
|
|
@ -2206,7 +2187,7 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
atomic64_inc_na(&mp->sfd->local_intf->stats->in.packets);
|
|
|
|
|
atomic64_add_na(&mp->sfd->local_intf->stats->in.bytes, mp->payload.len);
|
|
|
|
|
|
|
|
|
|
struct codec_ssrc_handler *input_ch = get_ssrc(ssrc_in_p->h.ssrc, &h->input_handler->ssrc_hash);
|
|
|
|
|
struct codec_ssrc_handler *input_ch = get_ssrc(ssrc_in->h.ssrc, &h->input_handler->ssrc_hash);
|
|
|
|
|
|
|
|
|
|
if (packet->bypass_seq) {
|
|
|
|
|
// bypass sequencer
|
|
|
|
|
@ -2225,13 +2206,13 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
__ssrc_lock_both(mp);
|
|
|
|
|
|
|
|
|
|
// get sequencer appropriate for our output
|
|
|
|
|
if (!ssrc_in_p->sequencers)
|
|
|
|
|
ssrc_in_p->sequencers = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __seq_free);
|
|
|
|
|
packet_sequencer_t *seq = g_hash_table_lookup(ssrc_in_p->sequencers, mp->media_out);
|
|
|
|
|
if (!ssrc_in->sequencers)
|
|
|
|
|
ssrc_in->sequencers = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL, __seq_free);
|
|
|
|
|
packet_sequencer_t *seq = g_hash_table_lookup(ssrc_in->sequencers, mp->media_out);
|
|
|
|
|
if (!seq) {
|
|
|
|
|
seq = g_new0(__typeof(*seq), 1);
|
|
|
|
|
packet_sequencer_init(seq, (GDestroyNotify) __transcode_packet_free);
|
|
|
|
|
g_hash_table_insert(ssrc_in_p->sequencers, mp->media_out, seq);
|
|
|
|
|
g_hash_table_insert(ssrc_in->sequencers, mp->media_out, seq);
|
|
|
|
|
// this is a quick fix to restore sequencer values until upper layer behavior will be fixed
|
|
|
|
|
unsigned int stats_ext_seq = atomic_get_na(&ssrc_in->stats->ext_seq);
|
|
|
|
|
if(stats_ext_seq) {
|
|
|
|
|
@ -2253,7 +2234,7 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Ignoring duplicate RTP packet");
|
|
|
|
|
if (func_ret != 1)
|
|
|
|
|
__transcode_packet_free(packet);
|
|
|
|
|
ssrc_in_p->duplicates++;
|
|
|
|
|
ssrc_in->duplicates++;
|
|
|
|
|
atomic64_inc_na(&mp->sfd->local_intf->stats->s.duplicates);
|
|
|
|
|
RTPE_STATS_INC(rtp_duplicates);
|
|
|
|
|
goto out;
|
|
|
|
|
@ -2317,18 +2298,18 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
|
|
|
|
|
// new packet might have different handlers
|
|
|
|
|
h = packet->handler;
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
obj_release(input_ch);
|
|
|
|
|
ch = get_ssrc(ssrc_in_p->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
ssrc_entry_release(input_ch);
|
|
|
|
|
ch = get_ssrc(ssrc_in->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
if (G_UNLIKELY(!ch))
|
|
|
|
|
goto next;
|
|
|
|
|
input_ch = get_ssrc(ssrc_in_p->h.ssrc, &h->input_handler->ssrc_hash);
|
|
|
|
|
input_ch = get_ssrc(ssrc_in->h.ssrc, &h->input_handler->ssrc_hash);
|
|
|
|
|
if (G_UNLIKELY(!input_ch)) {
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ssrc_in_p->packets_lost = seq->lost_count;
|
|
|
|
|
ssrc_in->packets_lost = seq->lost_count;
|
|
|
|
|
atomic_set_na(&ssrc_in->stats->ext_seq, seq->ext_seq);
|
|
|
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Processing RTP packet: seq %u, TS %lu",
|
|
|
|
|
@ -2336,7 +2317,7 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
|
|
|
|
|
if (seq_ret == 1) {
|
|
|
|
|
// seq reset - update output seq. we keep our output seq clean
|
|
|
|
|
ssrc_out_p->seq_diff -= packet->p.seq - seq_ori;
|
|
|
|
|
ssrc_out->seq_diff -= packet->p.seq - seq_ori;
|
|
|
|
|
seq_ret = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -2353,9 +2334,9 @@ next:
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
__ssrc_unlock_both(mp);
|
|
|
|
|
obj_release(input_ch);
|
|
|
|
|
ssrc_entry_release(input_ch);
|
|
|
|
|
out_ch:
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
|
|
|
|
|
mp->rtp = orig_rtp;
|
|
|
|
|
|
|
|
|
|
@ -2371,8 +2352,7 @@ void codec_output_rtp(struct media_packet *mp, struct codec_scheduler *csch,
|
|
|
|
|
unsigned long ts_delay)
|
|
|
|
|
{
|
|
|
|
|
struct rtp_header *rh = (void *) buf;
|
|
|
|
|
struct ssrc_ctx *ssrc_out = mp->ssrc_out;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out_p = ssrc_out->parent;
|
|
|
|
|
struct ssrc_entry_call *ssrc_out = mp->ssrc_out;
|
|
|
|
|
// reconstruct RTP header
|
|
|
|
|
unsigned long ts = payload_ts;
|
|
|
|
|
ZERO(*rh);
|
|
|
|
|
@ -2383,9 +2363,9 @@ void codec_output_rtp(struct media_packet *mp, struct codec_scheduler *csch,
|
|
|
|
|
if (seq != -1)
|
|
|
|
|
rh->seq_num = htons(seq);
|
|
|
|
|
else
|
|
|
|
|
rh->seq_num = htons(ntohs(mp->rtp->seq_num) + (ssrc_out_p->seq_diff += seq_inc));
|
|
|
|
|
rh->seq_num = htons(ntohs(mp->rtp->seq_num) + (ssrc_out->seq_diff += seq_inc));
|
|
|
|
|
rh->timestamp = htonl(ts);
|
|
|
|
|
rh->ssrc = htonl(ssrc_out_p->h.ssrc);
|
|
|
|
|
rh->ssrc = htonl(ssrc_out->h.ssrc);
|
|
|
|
|
|
|
|
|
|
// add to output queue
|
|
|
|
|
struct codec_packet *p = g_new0(__typeof(*p), 1);
|
|
|
|
|
@ -2398,7 +2378,7 @@ void codec_output_rtp(struct media_packet *mp, struct codec_scheduler *csch,
|
|
|
|
|
p->rtp = rh;
|
|
|
|
|
p->ts = ts;
|
|
|
|
|
p->clockrate = handler->dest_pt.clock_rate;
|
|
|
|
|
ssrc_ctx_hold(ssrc_out);
|
|
|
|
|
ssrc_entry_hold(ssrc_out);
|
|
|
|
|
p->ssrc_out = ssrc_out;
|
|
|
|
|
|
|
|
|
|
int64_t ts_diff_us = 0;
|
|
|
|
|
@ -2480,7 +2460,7 @@ static struct codec_ssrc_handler *__output_ssrc_handler(struct codec_ssrc_handle
|
|
|
|
|
// our encoder is in a different codec handler
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Switching context from decoder to encoder");
|
|
|
|
|
handler = handler->output_handler;
|
|
|
|
|
struct codec_ssrc_handler *new_ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, &handler->ssrc_hash);
|
|
|
|
|
struct codec_ssrc_handler *new_ch = get_ssrc(mp->ssrc_in->h.ssrc, &handler->ssrc_hash);
|
|
|
|
|
if (G_UNLIKELY(!new_ch)) {
|
|
|
|
|
ilogs(transcoding, LOG_ERR | LOG_FLAG_LIMIT,
|
|
|
|
|
"Switched from input to output codec context, but no codec handler present");
|
|
|
|
|
@ -2559,7 +2539,7 @@ static int codec_add_dtmf_packet(struct codec_ssrc_handler *ch, struct codec_ssr
|
|
|
|
|
payload_type = h->real_dtmf_payload_type;
|
|
|
|
|
|
|
|
|
|
skip:
|
|
|
|
|
obj_release(output_ch);
|
|
|
|
|
ssrc_entry_release(output_ch);
|
|
|
|
|
char *buf = bufferpool_alloc(media_bufferpool,
|
|
|
|
|
packet->payload->len + sizeof(struct rtp_header) + RTP_BUFFER_TAIL_ROOM);
|
|
|
|
|
memcpy(buf + sizeof(struct rtp_header), packet->payload->s, packet->payload->len);
|
|
|
|
|
@ -2569,7 +2549,7 @@ skip:
|
|
|
|
|
else // use our own sequencing
|
|
|
|
|
input_ch->codec_output_rtp_seq(mp, &ch->csch, packet->handler ? : h, buf, packet->payload->len, packet->ts,
|
|
|
|
|
packet->marker, payload_type, ts_delay);
|
|
|
|
|
mp->ssrc_out->parent->seq_diff++;
|
|
|
|
|
mp->ssrc_out->seq_diff++;
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -2694,12 +2674,12 @@ static tc_code packet_dtmf(struct codec_ssrc_handler *ch, struct codec_ssrc_hand
|
|
|
|
|
ret = TCC_CONSUMED;
|
|
|
|
|
else
|
|
|
|
|
ret = packet_dtmf_fwd(ch, input_ch, dup, mp);
|
|
|
|
|
mp->ssrc_out->parent->seq_diff++;
|
|
|
|
|
mp->ssrc_out->seq_diff++;
|
|
|
|
|
|
|
|
|
|
if (ret != TCC_CONSUMED)
|
|
|
|
|
__transcode_packet_free(dup);
|
|
|
|
|
}
|
|
|
|
|
mp->ssrc_out->parent->seq_diff--;
|
|
|
|
|
mp->ssrc_out->seq_diff--;
|
|
|
|
|
|
|
|
|
|
// discard the received event
|
|
|
|
|
do_blocking = true;
|
|
|
|
|
@ -2803,7 +2783,7 @@ void codec_packet_free(struct codec_packet *p) {
|
|
|
|
|
p->free_func(p->s.s);
|
|
|
|
|
if (p->plain_free_func && p->plain.s)
|
|
|
|
|
p->plain_free_func(p->plain.s);
|
|
|
|
|
ssrc_ctx_put(&p->ssrc_out);
|
|
|
|
|
ssrc_entry_release(p->ssrc_out);
|
|
|
|
|
g_free(p);
|
|
|
|
|
}
|
|
|
|
|
bool codec_packet_copy(struct codec_packet *p) {
|
|
|
|
|
@ -2819,7 +2799,7 @@ struct codec_packet *codec_packet_dup(struct codec_packet *p) {
|
|
|
|
|
dup->link.data = dup; // XXX obsolete this
|
|
|
|
|
codec_packet_copy(dup);
|
|
|
|
|
if (dup->ssrc_out)
|
|
|
|
|
ssrc_ctx_hold(dup->ssrc_out);
|
|
|
|
|
ssrc_entry_hold(dup->ssrc_out);
|
|
|
|
|
if (dup->rtp)
|
|
|
|
|
dup->rtp = (void *) dup->s.s;
|
|
|
|
|
return dup;
|
|
|
|
|
@ -2977,7 +2957,7 @@ static int handler_func_passthrough_ssrc(struct codec_handler *h, struct media_p
|
|
|
|
|
|
|
|
|
|
// check for DTMF injection
|
|
|
|
|
if (h->dtmf_payload_type != -1) {
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(mp->ssrc_in->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
if (ch) {
|
|
|
|
|
uint64_t ts64 = ntohl(mp->rtp->timestamp);
|
|
|
|
|
|
|
|
|
|
@ -3005,18 +2985,18 @@ static int handler_func_passthrough_ssrc(struct codec_handler *h, struct media_p
|
|
|
|
|
else if (!ch->dtmf_events.length)
|
|
|
|
|
ML_CLEAR(mp->media->monologue, DTMF_INJECTION_ACTIVE);
|
|
|
|
|
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// substitute out SSRC etc
|
|
|
|
|
mp->rtp->ssrc = htonl(mp->ssrc_out->parent->h.ssrc);
|
|
|
|
|
mp->rtp->ssrc = htonl(mp->ssrc_out->h.ssrc);
|
|
|
|
|
|
|
|
|
|
// to track our seq
|
|
|
|
|
unsigned short seq = ntohs(mp->rtp->seq_num);
|
|
|
|
|
|
|
|
|
|
while (true) {
|
|
|
|
|
mp->rtp->seq_num = htons(seq + mp->ssrc_out->parent->seq_diff);
|
|
|
|
|
mp->rtp->seq_num = htons(seq + mp->ssrc_out->seq_diff);
|
|
|
|
|
|
|
|
|
|
// keep track of other stats here?
|
|
|
|
|
|
|
|
|
|
@ -3025,7 +3005,7 @@ static int handler_func_passthrough_ssrc(struct codec_handler *h, struct media_p
|
|
|
|
|
if (duplicates == 0)
|
|
|
|
|
break;
|
|
|
|
|
duplicates--;
|
|
|
|
|
mp->ssrc_out->parent->seq_diff++;
|
|
|
|
|
mp->ssrc_out->seq_diff++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// restore original in case it was mangled
|
|
|
|
|
@ -3084,7 +3064,7 @@ uint64_t codec_last_dtmf_event(struct codec_ssrc_handler *ch) {
|
|
|
|
|
return ev->ts;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint64_t codec_encoder_pts(struct codec_ssrc_handler *ch, struct ssrc_ctx *ssrc_in) {
|
|
|
|
|
uint64_t codec_encoder_pts(struct codec_ssrc_handler *ch, struct ssrc_entry_call *ssrc_in) {
|
|
|
|
|
if (!ch || !ch->encoder) {
|
|
|
|
|
if (!ssrc_in)
|
|
|
|
|
return 0;
|
|
|
|
|
@ -3262,7 +3242,7 @@ static void __buffer_delay_seq(struct delay_buffer *dbuf, struct media_packet *m
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (__buffer_delay_do_direct(dbuf)) {
|
|
|
|
|
mp->ssrc_out->parent->seq_diff += seq_adj;
|
|
|
|
|
mp->ssrc_out->seq_diff += seq_adj;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -3271,7 +3251,7 @@ static void __buffer_delay_seq(struct delay_buffer *dbuf, struct media_packet *m
|
|
|
|
|
// peg the adjustment to the most recent frame if any
|
|
|
|
|
struct delay_frame *dframe = t_queue_peek_head(&dbuf->frames);
|
|
|
|
|
if (!dframe) {
|
|
|
|
|
mp->ssrc_out->parent->seq_diff += seq_adj;
|
|
|
|
|
mp->ssrc_out->seq_diff += seq_adj;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -3331,7 +3311,7 @@ static bool __buffer_dtx(struct dtx_buffer *dtxb, struct codec_ssrc_handler *dec
|
|
|
|
|
// schedule timer if not running yet
|
|
|
|
|
if (!dtxb->ct.next) {
|
|
|
|
|
if (!dtxb->ssrc)
|
|
|
|
|
dtxb->ssrc = mp->ssrc_in->parent->h.ssrc;
|
|
|
|
|
dtxb->ssrc = mp->ssrc_in->h.ssrc;
|
|
|
|
|
dtxb->ct.next = mp->tv;
|
|
|
|
|
dtxb->ct.next += rtpe_config.dtx_delay_us;
|
|
|
|
|
timerthread_obj_schedule_abs(&dtxb->ct.tt_obj, dtxb->ct.next);
|
|
|
|
|
@ -3368,8 +3348,8 @@ static void delay_frame_free(struct delay_frame *dframe) {
|
|
|
|
|
av_frame_free(&dframe->frame);
|
|
|
|
|
g_free(dframe->mp.raw.s);
|
|
|
|
|
media_packet_release(&dframe->mp);
|
|
|
|
|
obj_release(dframe->ch);
|
|
|
|
|
obj_release(dframe->input_ch);
|
|
|
|
|
ssrc_entry_release(dframe->ch);
|
|
|
|
|
ssrc_entry_release(dframe->input_ch);
|
|
|
|
|
if (dframe->packet)
|
|
|
|
|
__transcode_packet_free(dframe->packet);
|
|
|
|
|
g_free(dframe);
|
|
|
|
|
@ -3387,8 +3367,8 @@ static void dtx_packet_free(struct dtx_packet *dtxp) {
|
|
|
|
|
if (dtxp->packet)
|
|
|
|
|
__transcode_packet_free(dtxp->packet);
|
|
|
|
|
media_packet_release(&dtxp->mp);
|
|
|
|
|
obj_release(dtxp->decoder_handler);
|
|
|
|
|
obj_release(dtxp->input_handler);
|
|
|
|
|
ssrc_entry_release(dtxp->decoder_handler);
|
|
|
|
|
ssrc_entry_release(dtxp->input_handler);
|
|
|
|
|
g_free(dtxp);
|
|
|
|
|
}
|
|
|
|
|
static void delay_buffer_stop(struct delay_buffer **pcmbp) {
|
|
|
|
|
@ -3569,7 +3549,7 @@ static void __delay_frame_process(struct delay_buffer *dbuf, struct delay_frame
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (dframe->seq_adj)
|
|
|
|
|
dframe->mp.ssrc_out->parent->seq_diff += dframe->seq_adj;
|
|
|
|
|
dframe->mp.ssrc_out->seq_diff += dframe->seq_adj;
|
|
|
|
|
}
|
|
|
|
|
static void __delay_send_later(struct codec_timer *ct) {
|
|
|
|
|
struct delay_buffer *dbuf = (void *) ct;
|
|
|
|
|
@ -3809,7 +3789,7 @@ static void __dtx_send_later(struct codec_timer *ct) {
|
|
|
|
|
shutdown = true;
|
|
|
|
|
else if (!ps->ssrc_in[0])
|
|
|
|
|
shutdown = true;
|
|
|
|
|
else if (dtxb->ssrc != ps->ssrc_in[0]->parent->h.ssrc)
|
|
|
|
|
else if (dtxb->ssrc != ps->ssrc_in[0]->h.ssrc)
|
|
|
|
|
shutdown = true;
|
|
|
|
|
else if (dtxb->ct.next == 0)
|
|
|
|
|
shutdown = true;
|
|
|
|
|
@ -3886,13 +3866,13 @@ static void __dtx_send_later(struct codec_timer *ct) {
|
|
|
|
|
// packet consumed - track seq
|
|
|
|
|
rwlock_lock_r(&call->master_lock);
|
|
|
|
|
__ssrc_lock_both(&mp_copy);
|
|
|
|
|
mp_copy.ssrc_out->parent->seq_diff--;
|
|
|
|
|
mp_copy.ssrc_out->seq_diff--;
|
|
|
|
|
__ssrc_unlock_both(&mp_copy);
|
|
|
|
|
rwlock_unlock_r(&call->master_lock);
|
|
|
|
|
}
|
|
|
|
|
obj_release(call);
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
obj_release(input_ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
ssrc_entry_release(input_ch);
|
|
|
|
|
if (dtxp)
|
|
|
|
|
dtx_packet_free(dtxp);
|
|
|
|
|
media_packet_release(&mp_copy);
|
|
|
|
|
@ -3978,8 +3958,8 @@ static void __dtx_send_later(struct codec_timer *ct) {
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
obj_release(call);
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
obj_release(input_ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
ssrc_entry_release(input_ch);
|
|
|
|
|
if (dtxp)
|
|
|
|
|
dtx_packet_free(dtxp);
|
|
|
|
|
media_packet_release(&mp_copy);
|
|
|
|
|
@ -3997,7 +3977,7 @@ static void __dtx_shutdown(struct dtx_buffer *dtxb) {
|
|
|
|
|
ch->encoder->mux_dts = 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj_release(dtxb->csh);
|
|
|
|
|
ssrc_entry_release(dtxb->csh);
|
|
|
|
|
}
|
|
|
|
|
obj_release(dtxb->call);
|
|
|
|
|
t_queue_clear_full(&dtxb->packets, dtx_packet_free);
|
|
|
|
|
@ -4358,7 +4338,7 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
|
|
|
|
|
return &ch->h;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
static struct ssrc_entry *__ssrc_handler_decode_new(void *p) {
|
|
|
|
|
@ -4384,7 +4364,7 @@ static struct ssrc_entry *__ssrc_handler_decode_new(void *p) {
|
|
|
|
|
return &ch->h;
|
|
|
|
|
|
|
|
|
|
err:
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
static int __encoder_flush(encoder_t *enc, void *u1, void *u2) {
|
|
|
|
|
@ -4545,7 +4525,7 @@ static void packet_encoded_tx(AVPacket *pkt, struct codec_ssrc_handler *ch, stru
|
|
|
|
|
+ fraction_divl(pkt->pts, cr_fact),
|
|
|
|
|
ch->rtp_mark ? 1 : 0,
|
|
|
|
|
payload_type, ts_delay);
|
|
|
|
|
mp->ssrc_out->parent->seq_diff++;
|
|
|
|
|
mp->ssrc_out->seq_diff++;
|
|
|
|
|
ch->rtp_mark = 0;
|
|
|
|
|
if (!repeats)
|
|
|
|
|
break;
|
|
|
|
|
@ -4662,7 +4642,7 @@ static int packet_decoded_common(decoder_t *decoder, AVFrame *frame, void *u1, v
|
|
|
|
|
|
|
|
|
|
discard:
|
|
|
|
|
av_frame_free(&frame);
|
|
|
|
|
obj_release(new_ch);
|
|
|
|
|
ssrc_entry_release(new_ch);
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
@ -4836,33 +4816,29 @@ void codec_update_all_source_handlers(struct call_monologue *ml, const sdp_ng_fl
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void codec_calc_jitter(struct ssrc_ctx *ssrc, unsigned long ts, unsigned int clockrate, int64_t tv) {
|
|
|
|
|
void codec_calc_jitter(struct ssrc_entry_call *ssrc, unsigned long ts, unsigned int clockrate, int64_t tv) {
|
|
|
|
|
if (!ssrc || !clockrate)
|
|
|
|
|
return;
|
|
|
|
|
struct ssrc_entry_call *sec = ssrc->parent;
|
|
|
|
|
|
|
|
|
|
// RFC 3550 A.8
|
|
|
|
|
uint32_t transit = (((tv / 1000) * clockrate) / 1000) - ts;
|
|
|
|
|
mutex_lock(&sec->h.lock);
|
|
|
|
|
LOCK(&ssrc->h.lock);
|
|
|
|
|
int32_t d = 0;
|
|
|
|
|
if (sec->transit)
|
|
|
|
|
d = transit - sec->transit;
|
|
|
|
|
sec->transit = transit;
|
|
|
|
|
if (ssrc->transit)
|
|
|
|
|
d = transit - ssrc->transit;
|
|
|
|
|
ssrc->transit = transit;
|
|
|
|
|
if (d < 0)
|
|
|
|
|
d = -d;
|
|
|
|
|
// ignore implausibly large values
|
|
|
|
|
if (d < 100000)
|
|
|
|
|
sec->jitter += d - ((sec->jitter + 8) >> 4);
|
|
|
|
|
mutex_unlock(&sec->h.lock);
|
|
|
|
|
ssrc->jitter += d - ((ssrc->jitter + 8) >> 4);
|
|
|
|
|
}
|
|
|
|
|
static void codec_calc_lost(struct ssrc_ctx *ssrc, uint16_t seq) {
|
|
|
|
|
struct ssrc_entry_call *s = ssrc->parent;
|
|
|
|
|
|
|
|
|
|
LOCK(&s->h.lock);
|
|
|
|
|
static void codec_calc_lost(struct ssrc_entry_call *ssrc, uint16_t seq) {
|
|
|
|
|
LOCK(&ssrc->h.lock);
|
|
|
|
|
|
|
|
|
|
// XXX shared code from kernel module
|
|
|
|
|
|
|
|
|
|
uint32_t last_seq = s->last_seq_tracked;
|
|
|
|
|
uint32_t last_seq = ssrc->last_seq_tracked;
|
|
|
|
|
uint32_t new_seq = last_seq;
|
|
|
|
|
|
|
|
|
|
// old seq or seq reset?
|
|
|
|
|
@ -4873,8 +4849,8 @@ static void codec_calc_lost(struct ssrc_ctx *ssrc, uint16_t seq) {
|
|
|
|
|
else if (seq_diff > 0x100) {
|
|
|
|
|
// reset seq and loss tracker
|
|
|
|
|
new_seq = seq;
|
|
|
|
|
s->last_seq_tracked = seq;
|
|
|
|
|
s->lost_bits = -1;
|
|
|
|
|
ssrc->last_seq_tracked = seq;
|
|
|
|
|
ssrc->lost_bits = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
// seq wrap?
|
|
|
|
|
@ -4885,20 +4861,20 @@ static void codec_calc_lost(struct ssrc_ctx *ssrc, uint16_t seq) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
seq_diff = new_seq - last_seq;
|
|
|
|
|
s->last_seq_tracked = new_seq;
|
|
|
|
|
ssrc->last_seq_tracked = new_seq;
|
|
|
|
|
|
|
|
|
|
// shift loss tracker bit field and count losses
|
|
|
|
|
if (seq_diff >= (sizeof(s->lost_bits) * 8)) {
|
|
|
|
|
if (seq_diff >= (sizeof(ssrc->lost_bits) * 8)) {
|
|
|
|
|
// complete loss
|
|
|
|
|
s->packets_lost += sizeof(s->lost_bits) * 8;
|
|
|
|
|
s->lost_bits = -1;
|
|
|
|
|
ssrc->packets_lost += sizeof(ssrc->lost_bits) * 8;
|
|
|
|
|
ssrc->lost_bits = -1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
while (seq_diff) {
|
|
|
|
|
// shift out one bit and see if we lost it
|
|
|
|
|
if ((s->lost_bits & 0x80000000) == 0)
|
|
|
|
|
s->packets_lost++;
|
|
|
|
|
s->lost_bits <<= 1;
|
|
|
|
|
if ((ssrc->lost_bits & 0x80000000) == 0)
|
|
|
|
|
ssrc->packets_lost++;
|
|
|
|
|
ssrc->lost_bits <<= 1;
|
|
|
|
|
seq_diff--;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
@ -4906,8 +4882,8 @@ static void codec_calc_lost(struct ssrc_ctx *ssrc, uint16_t seq) {
|
|
|
|
|
|
|
|
|
|
// track this frame as being seen
|
|
|
|
|
seq_diff = (new_seq & 0xffff) - seq;
|
|
|
|
|
if (seq_diff < (sizeof(s->lost_bits) * 8))
|
|
|
|
|
s->lost_bits |= (1 << seq_diff);
|
|
|
|
|
if (seq_diff < (sizeof(ssrc->lost_bits) * 8))
|
|
|
|
|
ssrc->lost_bits |= (1 << seq_diff);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -4977,12 +4953,12 @@ static int handler_func_inject_dtmf(struct codec_handler *h, struct media_packet
|
|
|
|
|
h->input_handler = __input_handler(h, mp);
|
|
|
|
|
h->output_handler = h->input_handler;
|
|
|
|
|
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
struct codec_ssrc_handler *ch = get_ssrc(mp->ssrc_in->h.ssrc, &h->ssrc_hash);
|
|
|
|
|
if (!ch)
|
|
|
|
|
return 0;
|
|
|
|
|
decoder_input_data(ch->decoder, &mp->payload, mp->rtp->timestamp,
|
|
|
|
|
h->packet_decoded, ch, mp);
|
|
|
|
|
obj_release(ch);
|
|
|
|
|
ssrc_entry_release(ch);
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@ -6267,8 +6243,8 @@ static void codec_timers_run(void *p) {
|
|
|
|
|
#ifdef WITH_TRANSCODING
|
|
|
|
|
static void transcode_job_free(struct transcode_job *j) {
|
|
|
|
|
media_packet_release(&j->mp);
|
|
|
|
|
obj_release(j->ch);
|
|
|
|
|
obj_release(j->input_ch);
|
|
|
|
|
ssrc_entry_release(j->ch);
|
|
|
|
|
ssrc_entry_release(j->input_ch);
|
|
|
|
|
if (j->packet)
|
|
|
|
|
__transcode_packet_free(j->packet);
|
|
|
|
|
g_free(j);
|
|
|
|
|
|