|
|
|
@ -20,7 +20,15 @@ |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct codec_timer { |
|
|
|
struct timerthread_obj tt_obj; |
|
|
|
struct timeval next; |
|
|
|
void (*func)(struct codec_timer *); |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
static codec_handler_func handler_func_passthrough; |
|
|
|
static struct timerthread codec_timers_thread; |
|
|
|
|
|
|
|
static struct rtp_payload_type *__rtp_payload_type_copy(const struct rtp_payload_type *pt); |
|
|
|
static void __rtp_payload_type_dup(struct call *call, struct rtp_payload_type *pt); |
|
|
|
@ -69,7 +77,7 @@ struct codec_ssrc_handler; |
|
|
|
struct transcode_packet; |
|
|
|
|
|
|
|
struct dtx_buffer { |
|
|
|
struct timerthread_queue ttq; |
|
|
|
struct codec_timer ct; |
|
|
|
mutex_t lock; |
|
|
|
struct codec_ssrc_handler *csh; |
|
|
|
int ptime; // ms per packet |
|
|
|
@ -80,7 +88,6 @@ struct dtx_buffer { |
|
|
|
struct media_packet last_mp; |
|
|
|
unsigned long head_ts; |
|
|
|
uint32_t ssrc; |
|
|
|
struct timerthread_queue_entry ttq_entry; |
|
|
|
time_t start; |
|
|
|
}; |
|
|
|
struct dtx_packet { |
|
|
|
@ -151,21 +158,15 @@ struct codec_tracker { |
|
|
|
GHashTable *supp_codecs; // telephone-event etc => hash table of clock rates |
|
|
|
}; |
|
|
|
|
|
|
|
struct rtcp_timer_queue { |
|
|
|
struct timerthread_queue ttq; |
|
|
|
}; |
|
|
|
|
|
|
|
struct rtcp_timer { |
|
|
|
struct timerthread_queue_entry ttq_entry; |
|
|
|
struct codec_timer ct; |
|
|
|
struct call *call; |
|
|
|
struct call_media *media; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct timerthread codec_timers_thread; |
|
|
|
static struct rtcp_timer_queue *rtcp_timer_queue; |
|
|
|
|
|
|
|
|
|
|
|
static codec_handler_func handler_func_passthrough_ssrc; |
|
|
|
static codec_handler_func handler_func_transcode; |
|
|
|
static codec_handler_func handler_func_playback; |
|
|
|
@ -1176,38 +1177,40 @@ static void __rtcp_timer_free(void *p) { |
|
|
|
struct rtcp_timer *rt = p; |
|
|
|
if (rt->call) |
|
|
|
obj_put(rt->call); |
|
|
|
g_slice_free1(sizeof(*rt), rt); |
|
|
|
} |
|
|
|
static void __rtcp_timer_run(struct codec_timer *); |
|
|
|
// master lock held in W |
|
|
|
static void __codec_rtcp_timer_schedule(struct call_media *media) { |
|
|
|
struct rtcp_timer *rt = g_slice_alloc0(sizeof(*rt)); |
|
|
|
rt->ttq_entry.when = media->rtcp_timer; |
|
|
|
rt->call = obj_get(media->call); |
|
|
|
rt->media = media; |
|
|
|
struct rtcp_timer *rt = media->rtcp_timer; |
|
|
|
if (!rt) { |
|
|
|
media->rtcp_timer = rt = obj_alloc0("rtcp_timer", sizeof(*rt), __rtcp_timer_free); |
|
|
|
rt->ct.tt_obj.tt = &codec_timers_thread; |
|
|
|
rt->call = obj_get(media->call); |
|
|
|
rt->media = media; |
|
|
|
rt->ct.next = rtpe_now; |
|
|
|
rt->ct.func = __rtcp_timer_run; |
|
|
|
} |
|
|
|
|
|
|
|
timerthread_queue_push(&rtcp_timer_queue->ttq, &rt->ttq_entry); |
|
|
|
timeval_add_usec(&rt->ct.next, 5000000 + (ssl_random() % 2000000)); |
|
|
|
timerthread_obj_schedule_abs(&rt->ct.tt_obj, &rt->ct.next); |
|
|
|
} |
|
|
|
// no lock held |
|
|
|
static void __rtcp_timer_run(struct timerthread_queue *q, void *p) { |
|
|
|
struct rtcp_timer *rt = p; |
|
|
|
static void __rtcp_timer_run(struct codec_timer *ct) { |
|
|
|
struct rtcp_timer *rt = (void *) ct; |
|
|
|
|
|
|
|
// check scheduling |
|
|
|
rwlock_lock_w(&rt->call->master_lock); |
|
|
|
struct call_media *media = rt->media; |
|
|
|
struct timeval rtcp_timer = media->rtcp_timer; |
|
|
|
|
|
|
|
log_info_call(rt->call); |
|
|
|
|
|
|
|
if (!rtcp_timer.tv_sec || timeval_diff(&rtpe_now, &rtcp_timer) < 0 || !proto_is_rtp(media->protocol) |
|
|
|
|| !MEDIA_ISSET(media, RTCP_GEN)) |
|
|
|
{ |
|
|
|
media->rtcp_timer.tv_sec = 0; |
|
|
|
if (media->rtcp_timer != rt || !proto_is_rtp(media->protocol) || !MEDIA_ISSET(media, RTCP_GEN)) { |
|
|
|
if (media->rtcp_timer == rt) |
|
|
|
rtcp_timer_stop(&media->rtcp_timer); |
|
|
|
rwlock_unlock_w(&rt->call->master_lock); |
|
|
|
__rtcp_timer_free(rt); |
|
|
|
goto out; |
|
|
|
} |
|
|
|
timeval_add_usec(&rtcp_timer, 5000000 + (ssl_random() % 2000000)); |
|
|
|
media->rtcp_timer = rtcp_timer; |
|
|
|
timeval_add_usec(&ct->next, 5000000 + (ssl_random() % 2000000)); |
|
|
|
__codec_rtcp_timer_schedule(media); |
|
|
|
|
|
|
|
// switch locks to be more graceful |
|
|
|
@ -1233,18 +1236,13 @@ static void __rtcp_timer_run(struct timerthread_queue *q, void *p) { |
|
|
|
if (ssrc_out) |
|
|
|
obj_put(&ssrc_out->parent->h); |
|
|
|
|
|
|
|
__rtcp_timer_free(rt); |
|
|
|
|
|
|
|
out: |
|
|
|
log_info_clear(); |
|
|
|
} |
|
|
|
// master lock held in W |
|
|
|
static void __codec_rtcp_timer(struct call_media *receiver) { |
|
|
|
if (receiver->rtcp_timer.tv_sec) // already scheduled |
|
|
|
if (receiver->rtcp_timer) // already scheduled |
|
|
|
return; |
|
|
|
|
|
|
|
receiver->rtcp_timer = rtpe_now; |
|
|
|
timeval_add_usec(&receiver->rtcp_timer, 5000000 + (ssl_random() % 2000000)); |
|
|
|
__codec_rtcp_timer_schedule(receiver); |
|
|
|
// XXX unify with media player into a generic RTCP player |
|
|
|
} |
|
|
|
@ -1650,6 +1648,19 @@ static struct codec_handler *codec_handler_get_udptl(struct call_media *m) { |
|
|
|
#endif |
|
|
|
|
|
|
|
|
|
|
|
// master lock held in W |
|
|
|
static void codec_timer_stop(struct codec_timer **ctp) { |
|
|
|
if (!ctp || !*ctp) |
|
|
|
return; |
|
|
|
obj_put(&(*ctp)->tt_obj); |
|
|
|
*ctp = NULL; |
|
|
|
} |
|
|
|
// master lock held in W |
|
|
|
void rtcp_timer_stop(struct rtcp_timer **rtp) { |
|
|
|
codec_timer_stop((struct codec_timer **) rtp); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
// call must be locked in R |
|
|
|
struct codec_handler *codec_handler_get(struct call_media *m, int payload_type) { |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
@ -2411,12 +2422,12 @@ static int __buffer_dtx(struct dtx_buffer *dtxb, struct codec_ssrc_handler *deco |
|
|
|
ts, dtxb->packets.length); |
|
|
|
|
|
|
|
// schedule timer if not running yet |
|
|
|
if (!dtxb->ttq_entry.when.tv_sec) { |
|
|
|
if (!dtxb->ct.next.tv_sec) { |
|
|
|
if (!dtxb->ssrc) |
|
|
|
dtxb->ssrc = mp->ssrc_in->parent->h.ssrc; |
|
|
|
dtxb->ttq_entry.when = mp->tv; |
|
|
|
timeval_add_usec(&dtxb->ttq_entry.when, rtpe_config.dtx_delay * 1000); |
|
|
|
timerthread_queue_push(&dtxb->ttq, &dtxb->ttq_entry); |
|
|
|
dtxb->ct.next = mp->tv; |
|
|
|
timeval_add_usec(&dtxb->ct.next, rtpe_config.dtx_delay * 1000); |
|
|
|
timerthread_obj_schedule_abs(&dtxb->ct.tt_obj, &dtxb->ct.next); |
|
|
|
} |
|
|
|
|
|
|
|
mutex_unlock(&dtxb->lock); |
|
|
|
@ -2432,8 +2443,11 @@ static void dtx_packet_free(struct dtx_packet *dtxp) { |
|
|
|
obj_put(&dtxp->decoder_handler->h); |
|
|
|
g_slice_free1(sizeof(*dtxp), dtxp); |
|
|
|
} |
|
|
|
static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
struct dtx_buffer *dtxb = (void *) ttq; |
|
|
|
static void dtx_buffer_stop(struct dtx_buffer **dtxbp) { |
|
|
|
codec_timer_stop((struct codec_timer **) dtxbp); |
|
|
|
} |
|
|
|
static void __dtx_send_later(struct codec_timer *ct) { |
|
|
|
struct dtx_buffer *dtxb = (void *) ct; |
|
|
|
struct media_packet mp_copy = {0,}; |
|
|
|
int ret = 0, discard = 0; |
|
|
|
unsigned long ts; |
|
|
|
@ -2502,10 +2516,12 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
|
|
|
|
if (!call || !ch || !ps || !ps->ssrc_in |
|
|
|
|| dtxb->ssrc != ps->ssrc_in->parent->h.ssrc |
|
|
|
|| dtxb->ttq_entry.when.tv_sec == 0) { |
|
|
|
|| dtxb->ct.next.tv_sec == 0) { |
|
|
|
// shut down or SSRC change |
|
|
|
ilogs(dtx, LOG_DEBUG, "DTX buffer for %lx has been shut down", (unsigned long) dtxb->ssrc); |
|
|
|
dtxb->ttq_entry.when.tv_sec = 0; |
|
|
|
if (ch) |
|
|
|
dtx_buffer_stop(&ch->dtx_buffer); |
|
|
|
dtxb->ct.next.tv_sec = 0; |
|
|
|
dtxb->head_ts = 0; |
|
|
|
mutex_unlock(&dtxb->lock); |
|
|
|
goto out; // shut down |
|
|
|
@ -2518,7 +2534,7 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
"(%li ms < %i ms), " |
|
|
|
"pushing DTX timer forward my %i ms", |
|
|
|
tv_diff / 1000, rtpe_config.dtx_delay, rtpe_config.dtx_shift); |
|
|
|
timeval_add_usec(&dtxb->ttq_entry.when, rtpe_config.dtx_shift * 1000); |
|
|
|
timeval_add_usec(&dtxb->ct.next, rtpe_config.dtx_shift * 1000); |
|
|
|
} |
|
|
|
else if (dtxp && ts_diff < dtxb->tspp) { |
|
|
|
// TS underflow |
|
|
|
@ -2531,7 +2547,7 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
"(TS %lu, diff %li), " |
|
|
|
"pushing DTX timer forward by %i ms and discarding packet", |
|
|
|
ts, ts_diff, rtpe_config.dtx_shift); |
|
|
|
timeval_add_usec(&dtxb->ttq_entry.when, rtpe_config.dtx_shift * 1000); |
|
|
|
timeval_add_usec(&dtxb->ct.next, rtpe_config.dtx_shift * 1000); |
|
|
|
discard = 1; |
|
|
|
} |
|
|
|
} |
|
|
|
@ -2545,7 +2561,7 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
ilogs(dtx, LOG_DEBUG, "DTX timer queue overflowing (%i packets in queue, " |
|
|
|
"%lli ms delay), speeding up DTX timer by %i ms", |
|
|
|
dtxb->packets.length, ts_diff_us / 1000, rtpe_config.dtx_shift); |
|
|
|
timeval_add_usec(&dtxb->ttq_entry.when, rtpe_config.dtx_shift * -1000); |
|
|
|
timeval_add_usec(&dtxb->ct.next, rtpe_config.dtx_shift * -1000); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
@ -2604,8 +2620,8 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
} |
|
|
|
|
|
|
|
// schedule next run |
|
|
|
timeval_add_usec(&dtxb->ttq_entry.when, dtxb->ptime * 1000); |
|
|
|
timerthread_queue_push(&dtxb->ttq, &dtxb->ttq_entry); |
|
|
|
timeval_add_usec(&dtxb->ct.next, dtxb->ptime * 1000); |
|
|
|
timerthread_obj_schedule_abs(&dtxb->ct.tt_obj, &dtxb->ct.next); |
|
|
|
|
|
|
|
mutex_unlock(&dtxb->lock); |
|
|
|
|
|
|
|
@ -2663,8 +2679,9 @@ static void __dtx_setup(struct codec_ssrc_handler *ch) { |
|
|
|
return; |
|
|
|
|
|
|
|
struct dtx_buffer *dtx = |
|
|
|
ch->dtx_buffer = timerthread_queue_new("dtx_buffer", sizeof(*ch->dtx_buffer), |
|
|
|
&codec_timers_thread, NULL, __dtx_send_later, __dtx_free, NULL); |
|
|
|
ch->dtx_buffer = obj_alloc0("dtx_buffer", sizeof(*dtx), __dtx_free); |
|
|
|
dtx->ct.tt_obj.tt = &codec_timers_thread; |
|
|
|
dtx->ct.func = __dtx_send_later; |
|
|
|
dtx->csh = obj_get(&ch->h); |
|
|
|
dtx->call = obj_get(ch->handler->media->call); |
|
|
|
mutex_init(&dtx->lock); |
|
|
|
@ -2685,8 +2702,7 @@ static void __ssrc_handler_stop(void *p) { |
|
|
|
__dtx_shutdown(ch->dtx_buffer); |
|
|
|
mutex_unlock(&ch->dtx_buffer->lock); |
|
|
|
|
|
|
|
obj_put(&ch->dtx_buffer->ttq.tt_obj); |
|
|
|
ch->dtx_buffer = NULL; |
|
|
|
dtx_buffer_stop(&ch->dtx_buffer); |
|
|
|
} |
|
|
|
} |
|
|
|
void codec_handlers_stop(GQueue *q) { |
|
|
|
@ -2903,8 +2919,7 @@ static void __free_ssrc_handler(void *chp) { |
|
|
|
resample_shutdown(&ch->dtmf_resampler); |
|
|
|
g_queue_clear_full(&ch->dtmf_events, dtmf_event_free); |
|
|
|
g_queue_clear_full(&ch->silence_events, silence_event_free); |
|
|
|
if (ch->dtx_buffer) |
|
|
|
obj_put(&ch->dtx_buffer->ttq.tt_obj); |
|
|
|
dtx_buffer_stop(&ch->dtx_buffer); |
|
|
|
} |
|
|
|
|
|
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) { |
|
|
|
@ -3988,23 +4003,17 @@ void codec_rtp_payload_types(struct call_media *media, struct call_media *other_ |
|
|
|
g_hash_table_destroy(masked); |
|
|
|
} |
|
|
|
|
|
|
|
static void codec_timers_run(void *p) { |
|
|
|
struct codec_timer *ct = p; |
|
|
|
ct->func(ct); |
|
|
|
} |
|
|
|
|
|
|
|
void codecs_init(void) { |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
// XXX not real queue timer - unify to simple timerthread |
|
|
|
timerthread_init(&codec_timers_thread, timerthread_queue_run); |
|
|
|
rtcp_timer_queue = timerthread_queue_new("rtcp_timer_queue", sizeof(*rtcp_timer_queue), |
|
|
|
&codec_timers_thread, NULL, __rtcp_timer_run, NULL, __rtcp_timer_free); |
|
|
|
#endif |
|
|
|
timerthread_init(&codec_timers_thread, codec_timers_run); |
|
|
|
} |
|
|
|
void codecs_cleanup(void) { |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
obj_put(&rtcp_timer_queue->ttq.tt_obj); |
|
|
|
timerthread_free(&codec_timers_thread); |
|
|
|
#endif |
|
|
|
} |
|
|
|
void codec_timers_loop(void *p) { |
|
|
|
#ifdef WITH_TRANSCODING |
|
|
|
//ilog(LOG_DEBUG, "codec_timers_loop"); |
|
|
|
timerthread_run(&codec_timers_thread); |
|
|
|
#endif |
|
|
|
} |