|
|
|
@ -15,6 +15,7 @@
|
|
|
|
|
#include "t38.h"
|
|
|
|
|
#include "media_player.h"
|
|
|
|
|
#include "timerthread.h"
|
|
|
|
|
#include "log_funcs.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -63,6 +64,24 @@ static GList *__delete_receiver_codec(struct call_media *receiver, GList *link)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct codec_ssrc_handler;
|
|
|
|
|
|
|
|
|
|
struct dtx_buffer {
|
|
|
|
|
struct timerthread_queue ttq;
|
|
|
|
|
mutex_t lock;
|
|
|
|
|
struct codec_ssrc_handler *csh;
|
|
|
|
|
int ptime; // ms per packet
|
|
|
|
|
int tspp; // timestamp increment per packet
|
|
|
|
|
struct call *call;
|
|
|
|
|
unsigned long ts;
|
|
|
|
|
};
|
|
|
|
|
struct dtx_entry {
|
|
|
|
|
struct timerthread_queue_entry ttq_entry;
|
|
|
|
|
struct transcode_packet *packet;
|
|
|
|
|
struct media_packet mp;
|
|
|
|
|
unsigned long ts;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct codec_ssrc_handler {
|
|
|
|
|
struct ssrc_entry h; // must be first
|
|
|
|
|
struct codec_handler *handler;
|
|
|
|
@ -77,6 +96,7 @@ struct codec_ssrc_handler {
|
|
|
|
|
struct timeval first_send;
|
|
|
|
|
unsigned long first_send_ts;
|
|
|
|
|
GString *sample_buffer;
|
|
|
|
|
struct dtx_buffer *dtx_buffer;
|
|
|
|
|
|
|
|
|
|
// DTMF DSP stuff
|
|
|
|
|
dtmf_rx_state_t *dtmf_dsp;
|
|
|
|
@ -1380,7 +1400,7 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa
|
|
|
|
|
atomic64_set(&ssrc_in->packets_lost, ssrc_in_p->sequencer.lost_count);
|
|
|
|
|
atomic64_set(&ssrc_in->last_seq, ssrc_in_p->sequencer.ext_seq);
|
|
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Decoding RTP packet: seq %u, TS %lu",
|
|
|
|
|
ilog(LOG_DEBUG, "Processing RTP packet: seq %u, TS %lu",
|
|
|
|
|
packet->p.seq, packet->ts);
|
|
|
|
|
|
|
|
|
|
if (seq_ret == 1) {
|
|
|
|
@ -1834,6 +1854,153 @@ static int codec_decoder_event(enum codec_event event, void *ptr, void *data) {
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __dtx_add_callback(struct dtx_buffer *dtxb, const struct timeval *base, unsigned int offset,
|
|
|
|
|
const struct media_packet *mp, unsigned long ts, int seq_add)
|
|
|
|
|
{
|
|
|
|
|
struct dtx_entry *dtxe = g_slice_alloc0(sizeof(*dtxe));
|
|
|
|
|
dtxe->ttq_entry.when = *base;
|
|
|
|
|
timeval_add_usec(&dtxe->ttq_entry.when, offset);
|
|
|
|
|
dtxe->ts = ts;
|
|
|
|
|
media_packet_copy(&dtxe->mp, mp);
|
|
|
|
|
dtxe->mp.rtp->seq_num += htons(seq_add);
|
|
|
|
|
timerthread_queue_push(&dtxb->ttq, &dtxe->ttq_entry);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void __dtx_entry_free(void *p) {
|
|
|
|
|
struct dtx_entry *dtxe = p;
|
|
|
|
|
if (dtxe->packet)
|
|
|
|
|
__transcode_packet_free(dtxe->packet);
|
|
|
|
|
media_packet_release(&dtxe->mp);
|
|
|
|
|
g_slice_free1(sizeof(*dtxe), dtxe);
|
|
|
|
|
}
|
|
|
|
|
static void __dtx_send_later(struct timerthread_queue *ttq, void *p) {
|
|
|
|
|
struct dtx_buffer *dtxb = (void *) ttq;
|
|
|
|
|
struct dtx_entry *dtxe = p;
|
|
|
|
|
struct transcode_packet *packet = dtxe->packet;
|
|
|
|
|
struct media_packet *mp = &dtxe->mp;
|
|
|
|
|
struct packet_stream *ps = mp->stream;
|
|
|
|
|
struct packet_stream *sink = ps->rtp_sink;
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock);
|
|
|
|
|
struct codec_ssrc_handler *ch = dtxb->csh ? obj_get(&dtxb->csh->h) : NULL;
|
|
|
|
|
struct call *call = dtxb->call ? obj_get(dtxb->call) : NULL;
|
|
|
|
|
mutex_unlock(&dtxb->lock);
|
|
|
|
|
|
|
|
|
|
if (!call)
|
|
|
|
|
goto out; // shut down
|
|
|
|
|
|
|
|
|
|
log_info_stream_fd(mp->sfd);
|
|
|
|
|
|
|
|
|
|
rwlock_lock_r(&call->master_lock);
|
|
|
|
|
__ssrc_lock_both(mp);
|
|
|
|
|
|
|
|
|
|
if (packet) {
|
|
|
|
|
ilog(LOG_DEBUG, "Decoding DTX-buffered RTP packet (TS %lu) now", packet->ts);
|
|
|
|
|
|
|
|
|
|
ret = decoder_input_data(ch->decoder, packet->payload, packet->ts,
|
|
|
|
|
ch->handler->packet_decoded, ch, &dtxe->mp);
|
|
|
|
|
mp->ssrc_out->parent->seq_diff--;
|
|
|
|
|
if (ret)
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Decoder error while processing buffered RTP packet");
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
unsigned long dtxe_ts = dtxe->ts;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock);
|
|
|
|
|
unsigned long dtxb_ts = dtxb->ts;
|
|
|
|
|
|
|
|
|
|
if (dtxe_ts == dtxb_ts) {
|
|
|
|
|
ilog(LOG_DEBUG, "RTP media for TS %lu+ missing, triggering DTX",
|
|
|
|
|
dtxe_ts);
|
|
|
|
|
|
|
|
|
|
dtxb_ts += dtxb->tspp;
|
|
|
|
|
dtxe_ts = dtxb_ts;
|
|
|
|
|
dtxb->ts = dtxb_ts;
|
|
|
|
|
mutex_unlock(&dtxb->lock);
|
|
|
|
|
|
|
|
|
|
ret = decoder_lost_packet(ch->decoder, dtxe_ts,
|
|
|
|
|
ch->handler->packet_decoded, ch, &dtxe->mp);
|
|
|
|
|
if (ret)
|
|
|
|
|
ilog(LOG_WARN | LOG_FLAG_LIMIT, "Decoder error handling DTX/lost packet");
|
|
|
|
|
|
|
|
|
|
__dtx_add_callback(dtxb, &dtxe->ttq_entry.when, dtxb->ptime * 1000, mp, dtxe_ts, 0);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
mutex_unlock(&dtxb->lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
__ssrc_unlock_both(mp);
|
|
|
|
|
|
|
|
|
|
if (mp->packets_out.length && ret == 0) {
|
|
|
|
|
if (ps->handler && media_packet_encrypt(ps->handler->out->rtp_crypt, sink, mp))
|
|
|
|
|
ilog(LOG_ERR | LOG_FLAG_LIMIT, "Error encrypting buffered RTP media");
|
|
|
|
|
|
|
|
|
|
mutex_lock(&sink->out_lock);
|
|
|
|
|
if (media_socket_dequeue(mp, sink))
|
|
|
|
|
ilog(LOG_ERR | LOG_FLAG_LIMIT, "Error sending buffered media to RTP sink");
|
|
|
|
|
mutex_unlock(&sink->out_lock);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rwlock_unlock_r(&call->master_lock);
|
|
|
|
|
obj_put(call);
|
|
|
|
|
obj_put(&ch->h);
|
|
|
|
|
|
|
|
|
|
out:
|
|
|
|
|
__dtx_entry_free(dtxe);
|
|
|
|
|
log_info_clear();
|
|
|
|
|
}
|
|
|
|
|
static void __dtx_shutdown(struct dtx_buffer *dtxb) {
|
|
|
|
|
if (dtxb->csh)
|
|
|
|
|
obj_put(&dtxb->csh->h);
|
|
|
|
|
dtxb->csh = NULL;
|
|
|
|
|
if (dtxb->call)
|
|
|
|
|
obj_put(dtxb->call);
|
|
|
|
|
dtxb->call = NULL;
|
|
|
|
|
}
|
|
|
|
|
static void __dtx_free(void *p) {
|
|
|
|
|
struct dtx_buffer *dtxb = p;
|
|
|
|
|
ilog(LOG_DEBUG, "__dtx_free");
|
|
|
|
|
__dtx_shutdown(dtxb);
|
|
|
|
|
mutex_destroy(&dtxb->lock);
|
|
|
|
|
}
|
|
|
|
|
static void __dtx_setup(struct codec_ssrc_handler *ch) {
|
|
|
|
|
if (!ch->handler->source_pt.codec_def->packet_lost || ch->dtx_buffer)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
if (!rtpe_config.dtx_delay)
|
|
|
|
|
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, __dtx_entry_free);
|
|
|
|
|
dtx->csh = obj_get(&ch->h);
|
|
|
|
|
dtx->call = obj_get(ch->handler->media->call);
|
|
|
|
|
mutex_init(&dtx->lock);
|
|
|
|
|
dtx->ptime = ch->ptime;
|
|
|
|
|
if (!dtx->ptime)
|
|
|
|
|
dtx->ptime = 20; // XXX ?
|
|
|
|
|
dtx->tspp = dtx->ptime * ch->handler->source_pt.clock_rate / 1000;
|
|
|
|
|
}
|
|
|
|
|
void __ssrc_handler_stop(void *p) {
|
|
|
|
|
struct codec_ssrc_handler *ch = p;
|
|
|
|
|
if (ch->dtx_buffer) {
|
|
|
|
|
mutex_lock(&ch->dtx_buffer->lock);
|
|
|
|
|
__dtx_shutdown(ch->dtx_buffer);
|
|
|
|
|
mutex_unlock(&ch->dtx_buffer->lock);
|
|
|
|
|
|
|
|
|
|
obj_put(&ch->dtx_buffer->ttq.tt_obj);
|
|
|
|
|
ch->dtx_buffer = NULL;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
void codec_handlers_stop(GQueue *q) {
|
|
|
|
|
for (GList *l = q->head; l; l = l->next) {
|
|
|
|
|
struct codec_handler *h = l->data;
|
|
|
|
|
ssrc_hash_foreach(h->ssrc_hash, __ssrc_handler_stop);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
|
|
|
|
|
struct codec_handler *h = p;
|
|
|
|
|
|
|
|
|
@ -1894,6 +2061,8 @@ static struct ssrc_entry *__ssrc_handler_transcode_new(void *p) {
|
|
|
|
|
ch->bytes_per_packet = (ch->encoder->samples_per_packet ? : ch->encoder->samples_per_frame)
|
|
|
|
|
* h->dest_pt.codec_def->bits_per_sample / 8;
|
|
|
|
|
|
|
|
|
|
__dtx_setup(ch);
|
|
|
|
|
|
|
|
|
|
ilog(LOG_DEBUG, "Encoder created with clockrate %i, %i channels, using sample format %i "
|
|
|
|
|
"(ptime %i for %i samples per frame and %i samples (%i bytes) per packet, bitrate %i)",
|
|
|
|
|
ch->encoder_format.clockrate, ch->encoder_format.channels, ch->encoder_format.format,
|
|
|
|
@ -1930,6 +2099,8 @@ static void __free_ssrc_handler(void *chp) {
|
|
|
|
|
dtmf_rx_free(ch->dtmf_dsp);
|
|
|
|
|
resample_shutdown(&ch->dtmf_resampler);
|
|
|
|
|
g_queue_clear_full(&ch->dtmf_events, dtmf_event_free);
|
|
|
|
|
if (ch->dtx_buffer)
|
|
|
|
|
obj_put(&ch->dtx_buffer->ttq.tt_obj);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) {
|
|
|
|
@ -2116,11 +2287,43 @@ static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, v
|
|
|
|
|
|
|
|
|
|
static int packet_decode(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp)
|
|
|
|
|
{
|
|
|
|
|
int ret = 0;
|
|
|
|
|
|
|
|
|
|
if (!ch->first_ts)
|
|
|
|
|
ch->first_ts = packet->ts;
|
|
|
|
|
int ret = decoder_input_data(ch->decoder, packet->payload, packet->ts, ch->handler->packet_decoded, ch, mp);
|
|
|
|
|
//mp->iter_in++;
|
|
|
|
|
mp->ssrc_out->parent->seq_diff--;
|
|
|
|
|
|
|
|
|
|
if (ch->dtx_buffer && mp->sfd && mp->ssrc_in && mp->ssrc_out) {
|
|
|
|
|
ilog(LOG_DEBUG, "Adding packet to DTX buffer");
|
|
|
|
|
|
|
|
|
|
struct dtx_buffer *dtxb = ch->dtx_buffer;
|
|
|
|
|
unsigned long ts = packet->ts;
|
|
|
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock);
|
|
|
|
|
if (ts != dtxb->ts)
|
|
|
|
|
dtxb->ts = ts;
|
|
|
|
|
mutex_unlock(&dtxb->lock);
|
|
|
|
|
|
|
|
|
|
struct dtx_entry *dtxe = g_slice_alloc0(sizeof(*dtxe));
|
|
|
|
|
dtxe->ttq_entry.when = rtpe_now;
|
|
|
|
|
timeval_add_usec(&dtxe->ttq_entry.when, rtpe_config.dtx_delay * 1000);
|
|
|
|
|
dtxe->packet = packet;
|
|
|
|
|
media_packet_copy(&dtxe->mp, mp);
|
|
|
|
|
timerthread_queue_push(&dtxb->ttq, &dtxe->ttq_entry);
|
|
|
|
|
// packet now consumed
|
|
|
|
|
packet = NULL;
|
|
|
|
|
|
|
|
|
|
__dtx_add_callback(dtxb, &rtpe_now, (rtpe_config.dtx_delay + dtxb->ptime) * 1000, mp, ts, 1);
|
|
|
|
|
|
|
|
|
|
ret = 1;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
ilog(LOG_DEBUG, "Decoding RTP packet now");
|
|
|
|
|
ret = decoder_input_data(ch->decoder, packet->payload, packet->ts, ch->handler->packet_decoded,
|
|
|
|
|
ch, mp);
|
|
|
|
|
ret = ret ? -1 : 0;
|
|
|
|
|
mp->ssrc_out->parent->seq_diff--;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|