|
|
|
@ -75,6 +75,7 @@ struct dtx_buffer { |
|
|
|
int tspp; // timestamp increment per packet |
|
|
|
struct call *call; |
|
|
|
unsigned long ts; |
|
|
|
unsigned int ts_seq; // for subsequent packets with same TS, e.g. DTMF |
|
|
|
time_t start; |
|
|
|
}; |
|
|
|
struct dtx_entry { |
|
|
|
@ -83,6 +84,8 @@ struct dtx_entry { |
|
|
|
struct media_packet mp; |
|
|
|
unsigned long ts; |
|
|
|
void *ssrc_ptr; // opaque pointer, doesn't hold a reference |
|
|
|
struct codec_ssrc_handler *decoder_handler; // holds reference |
|
|
|
int (*func)(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp); |
|
|
|
}; |
|
|
|
|
|
|
|
struct silence_event { |
|
|
|
@ -177,6 +180,11 @@ static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, v |
|
|
|
|
|
|
|
static void codec_touched(struct rtp_payload_type *pt, struct call_media *media); |
|
|
|
|
|
|
|
static int __buffer_dtx(struct dtx_buffer *dtxb, struct codec_ssrc_handler *ch, |
|
|
|
struct transcode_packet *packet, struct media_packet *mp, |
|
|
|
int (*func)(struct codec_ssrc_handler *ch, struct transcode_packet *packet, |
|
|
|
struct media_packet *mp)); |
|
|
|
|
|
|
|
|
|
|
|
static struct codec_handler codec_handler_stub_ssrc = { |
|
|
|
.source_pt.payload_type = -1, |
|
|
|
@ -1923,8 +1931,8 @@ static struct codec_ssrc_handler *__output_ssrc_handler(struct codec_ssrc_handle |
|
|
|
return new_ch; |
|
|
|
} |
|
|
|
|
|
|
|
static void packet_dtmf_fwd(struct codec_ssrc_handler *ch, struct transcode_packet *packet, |
|
|
|
struct media_packet *mp, int seq_inc) |
|
|
|
static int packet_dtmf_fwd(struct codec_ssrc_handler *ch, struct transcode_packet *packet, |
|
|
|
struct media_packet *mp) |
|
|
|
{ |
|
|
|
int payload_type = -1; // take from handler's output config |
|
|
|
|
|
|
|
@ -1986,10 +1994,46 @@ skip:; |
|
|
|
packet->marker, packet->p.seq, -1, payload_type); |
|
|
|
else // use our own sequencing |
|
|
|
__output_rtp(mp, ch, packet->handler ? : ch->handler, buf, packet->payload->len, packet->ts, |
|
|
|
packet->marker, -1, seq_inc, payload_type); |
|
|
|
packet->marker, -1, 0, payload_type); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
// returns the codec handler for the primary payload type - mostly determined by guessing |
|
|
|
static struct codec_handler *__decoder_handler(struct codec_handler *h, struct media_packet *mp) { |
|
|
|
if (!mp->ssrc_in) |
|
|
|
return h; |
|
|
|
|
|
|
|
for (int i = 0; i < mp->ssrc_in->tracker.most_len; i++) { |
|
|
|
int prim_pt = mp->ssrc_in->tracker.most[i]; |
|
|
|
if (prim_pt == 255) |
|
|
|
continue; |
|
|
|
|
|
|
|
struct codec_handler *sequencer_h = codec_handler_get(mp->media, prim_pt); |
|
|
|
if (sequencer_h == h) |
|
|
|
continue; |
|
|
|
if (sequencer_h->source_pt.codec_def && sequencer_h->source_pt.codec_def->supplemental) |
|
|
|
continue; |
|
|
|
ilogs(transcoding, LOG_DEBUG, "Primary RTP payload type for handling %s is %i", |
|
|
|
h->source_pt.codec_def->rtpname, |
|
|
|
prim_pt); |
|
|
|
return sequencer_h; |
|
|
|
} |
|
|
|
return h; |
|
|
|
} |
|
|
|
|
|
|
|
static int packet_dtmf(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp) |
|
|
|
{ |
|
|
|
struct codec_ssrc_handler *decoder_ch = NULL; |
|
|
|
|
|
|
|
if (mp->ssrc_in) { |
|
|
|
// find our decoder handler for the appropriate DTX buffer |
|
|
|
struct codec_handler *handler = ch->handler; |
|
|
|
struct codec_handler *decoder_handler = __decoder_handler(handler, mp); |
|
|
|
decoder_ch = get_ssrc(mp->ssrc_in->parent->h.ssrc, |
|
|
|
decoder_handler->ssrc_hash); |
|
|
|
} |
|
|
|
|
|
|
|
if (ch->ts_in != packet->ts) { // ignore already processed events |
|
|
|
int ret = dtmf_event(mp, packet->payload, ch->encoder_format.clockrate); |
|
|
|
if (G_UNLIKELY(ret == -1)) // error |
|
|
|
@ -2000,15 +2044,25 @@ static int packet_dtmf(struct codec_ssrc_handler *ch, struct transcode_packet *p |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
if (!mp->call->block_dtmf && !mp->media->monologue->block_dtmf) |
|
|
|
packet_dtmf_fwd(ch, packet, mp, 0); |
|
|
|
return 0; |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
if (!mp->call->block_dtmf && !mp->media->monologue->block_dtmf) { |
|
|
|
if (decoder_ch && __buffer_dtx(decoder_ch->dtx_buffer, ch, packet, mp, packet_dtmf_fwd)) |
|
|
|
ret = 1; // consumed |
|
|
|
else |
|
|
|
packet_dtmf_fwd(ch, packet, mp); |
|
|
|
} |
|
|
|
|
|
|
|
if (decoder_ch) |
|
|
|
obj_put(&decoder_ch->h); |
|
|
|
|
|
|
|
return ret; |
|
|
|
} |
|
|
|
static int packet_dtmf_dup(struct codec_ssrc_handler *ch, struct transcode_packet *packet, |
|
|
|
struct media_packet *mp) |
|
|
|
{ |
|
|
|
if (!mp->call->block_dtmf && !mp->media->monologue->block_dtmf) |
|
|
|
packet_dtmf_fwd(ch, packet, mp, 0); |
|
|
|
packet_dtmf_fwd(ch, packet, mp); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
@ -2031,24 +2085,7 @@ static int __handler_func_supplemental(struct codec_handler *h, struct media_pac |
|
|
|
// determine the primary audio codec used by this SSRC, as the sequence numbers |
|
|
|
// and timing info is shared with it. we'll need to use the same sequencer |
|
|
|
|
|
|
|
struct codec_handler *sequencer_h = h; // handler that contains the appropriate sequencer |
|
|
|
if (mp->ssrc_in) { |
|
|
|
for (int i = 0; i < mp->ssrc_in->tracker.most_len; i++) { |
|
|
|
int prim_pt = mp->ssrc_in->tracker.most[i]; |
|
|
|
if (prim_pt == 255) |
|
|
|
continue; |
|
|
|
|
|
|
|
sequencer_h = codec_handler_get(mp->media, prim_pt); |
|
|
|
if (sequencer_h == h) |
|
|
|
continue; |
|
|
|
if (sequencer_h->source_pt.codec_def && sequencer_h->source_pt.codec_def->supplemental) |
|
|
|
continue; |
|
|
|
ilogs(transcoding, LOG_DEBUG, "Primary RTP payload type for handling %s is %i", |
|
|
|
h->source_pt.codec_def->rtpname, |
|
|
|
prim_pt); |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
struct codec_handler *sequencer_h = __decoder_handler(h, mp); |
|
|
|
|
|
|
|
// XXX ? h->output_handler = sequencer_h->output_handler; // XXX locking? |
|
|
|
|
|
|
|
@ -2295,12 +2332,55 @@ static void __dtx_add_callback(struct dtx_buffer *dtxb, const struct timeval *ba |
|
|
|
dtxe->ssrc_ptr = ssrc_ptr; |
|
|
|
timerthread_queue_push(&dtxb->ttq, &dtxe->ttq_entry); |
|
|
|
} |
|
|
|
// consumes `packet` if buffered (returns 1) |
|
|
|
static int __buffer_dtx(struct dtx_buffer *dtxb, struct codec_ssrc_handler *decoder_handler, |
|
|
|
struct transcode_packet *packet, struct media_packet *mp, |
|
|
|
int (*func)(struct codec_ssrc_handler *ch, struct transcode_packet *packet, |
|
|
|
struct media_packet *mp)) |
|
|
|
{ |
|
|
|
if (!dtxb || !mp->sfd || !mp->ssrc_in || !mp->ssrc_out) |
|
|
|
return 0; |
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Adding packet to DTX buffer"); |
|
|
|
|
|
|
|
unsigned long ts = packet->ts; |
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock); |
|
|
|
if (ts != dtxb->ts) { |
|
|
|
dtxb->ts = ts; |
|
|
|
dtxb->ts_seq = 0; |
|
|
|
} |
|
|
|
else |
|
|
|
dtxb->ts_seq++; |
|
|
|
unsigned int ts_seq = dtxb->ts_seq; |
|
|
|
dtxb->start = rtpe_now.tv_sec; |
|
|
|
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; |
|
|
|
dtxe->func = func; |
|
|
|
if (decoder_handler) |
|
|
|
dtxe->decoder_handler = obj_get(&decoder_handler->h); |
|
|
|
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 + ts_seq, 1, |
|
|
|
mp->stream->ssrc_in); |
|
|
|
|
|
|
|
return 1; |
|
|
|
} |
|
|
|
|
|
|
|
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); |
|
|
|
if (dtxe->decoder_handler) |
|
|
|
obj_put(&dtxe->decoder_handler->h); |
|
|
|
g_slice_free1(sizeof(*dtxe), dtxe); |
|
|
|
} |
|
|
|
static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
@ -2312,11 +2392,13 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock); |
|
|
|
struct codec_ssrc_handler *ch = dtxb->csh ? obj_get(&dtxb->csh->h) : NULL; |
|
|
|
struct codec_ssrc_handler *ch = dtxe->decoder_handler ? obj_get(&dtxe->decoder_handler->h) : NULL; |
|
|
|
if (!ch && dtxb->csh) |
|
|
|
ch = obj_get(&dtxb->csh->h); |
|
|
|
struct call *call = dtxb->call ? obj_get(dtxb->call) : NULL; |
|
|
|
mutex_unlock(&dtxb->lock); |
|
|
|
|
|
|
|
if (!call) |
|
|
|
if (!call || !ch) |
|
|
|
goto out; // shut down |
|
|
|
|
|
|
|
log_info_stream_fd(mp->sfd); |
|
|
|
@ -2327,9 +2409,7 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
if (packet) { |
|
|
|
ilogs(transcoding, 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--; |
|
|
|
ret = dtxe->func(ch, packet, &dtxe->mp); |
|
|
|
if (ret) |
|
|
|
ilogs(transcoding, LOG_WARN | LOG_FLAG_LIMIT, "Decoder error while processing buffered RTP packet"); |
|
|
|
} |
|
|
|
@ -2338,7 +2418,7 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
|
|
|
|
mutex_lock(&dtxb->lock); |
|
|
|
unsigned int diff = rtpe_now.tv_sec - dtxb->start; |
|
|
|
unsigned long dtxb_ts = dtxb->ts; |
|
|
|
unsigned long dtxb_ts = dtxb->ts + dtxb->ts_seq; |
|
|
|
void *ssrc_ptr = dtxe->mp.stream->ssrc_in; |
|
|
|
|
|
|
|
if (dtxe_ts == dtxb_ts |
|
|
|
@ -2349,8 +2429,10 @@ static void __dtx_send_later(struct timerthread_queue *ttq, void *p) { |
|
|
|
dtxe_ts); |
|
|
|
|
|
|
|
dtxb_ts += dtxb->tspp; |
|
|
|
dtxb_ts -= dtxb->ts_seq; |
|
|
|
dtxe_ts = dtxb_ts; |
|
|
|
dtxb->ts = dtxb_ts; |
|
|
|
dtxb->ts_seq = 0; |
|
|
|
mutex_unlock(&dtxb->lock); |
|
|
|
|
|
|
|
ret = decoder_lost_packet(ch->decoder, dtxe_ts, |
|
|
|
@ -2837,6 +2919,13 @@ static int packet_decoded_direct(decoder_t *decoder, AVFrame *frame, void *u1, v |
|
|
|
return packet_decoded_common(decoder, frame, u1, u2, encoder_input_data); |
|
|
|
} |
|
|
|
|
|
|
|
static int __rtp_decode(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp) |
|
|
|
{ |
|
|
|
int ret = decoder_input_data(ch->decoder, packet->payload, packet->ts, ch->handler->packet_decoded, |
|
|
|
ch, mp); |
|
|
|
mp->ssrc_out->parent->seq_diff--; |
|
|
|
return ret; |
|
|
|
} |
|
|
|
static int packet_decode(struct codec_ssrc_handler *ch, struct transcode_packet *packet, struct media_packet *mp) |
|
|
|
{ |
|
|
|
int ret = 0; |
|
|
|
@ -2845,38 +2934,12 @@ static int packet_decode(struct codec_ssrc_handler *ch, struct transcode_packet |
|
|
|
ch->first_ts = packet->ts; |
|
|
|
ch->last_ts = packet->ts; |
|
|
|
|
|
|
|
if (ch->dtx_buffer && mp->sfd && mp->ssrc_in && mp->ssrc_out) { |
|
|
|
ilogs(transcoding, 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; |
|
|
|
dtxb->start = rtpe_now.tv_sec; |
|
|
|
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, |
|
|
|
mp->stream->ssrc_in); |
|
|
|
|
|
|
|
ret = 1; |
|
|
|
} |
|
|
|
if (__buffer_dtx(ch->dtx_buffer, ch, packet, mp, __rtp_decode)) |
|
|
|
ret = 1; // consumed |
|
|
|
else { |
|
|
|
ilogs(transcoding, LOG_DEBUG, "Decoding RTP packet now"); |
|
|
|
ret = decoder_input_data(ch->decoder, packet->payload, packet->ts, ch->handler->packet_decoded, |
|
|
|
ch, mp); |
|
|
|
ret = __rtp_decode(ch, packet, mp); |
|
|
|
ret = ret ? -1 : 0; |
|
|
|
mp->ssrc_out->parent->seq_diff--; |
|
|
|
} |
|
|
|
|
|
|
|
return ret; |
|
|
|
|