|
|
|
@ -174,11 +174,7 @@ struct codec_ssrc_handler { |
|
|
|
int bitrate; |
|
|
|
int ptime; |
|
|
|
int bytes_per_packet; |
|
|
|
unsigned long first_ts; // for output TS scaling |
|
|
|
unsigned long last_ts; // to detect input lag and handle lost packets |
|
|
|
struct timeval first_send; |
|
|
|
unsigned long first_send_ts; |
|
|
|
long output_skew; |
|
|
|
struct codec_scheduler csch; |
|
|
|
GString *sample_buffer; |
|
|
|
struct dtx_buffer *dtx_buffer; |
|
|
|
|
|
|
|
@ -513,9 +509,9 @@ struct codec_handler *codec_handler_make_playback(const struct rtp_payload_type |
|
|
|
rtp_payload_type_copy(&handler->dest_pt, dst_pt); |
|
|
|
handler->handler_func = handler_func_playback; |
|
|
|
handler->ssrc_handler = (void *) __ssrc_handler_transcode_new(handler); |
|
|
|
handler->ssrc_handler->first_ts = last_ts; |
|
|
|
while (handler->ssrc_handler->first_ts == 0) |
|
|
|
handler->ssrc_handler->first_ts = ssl_random(); |
|
|
|
handler->ssrc_handler->csch.first_ts = last_ts; |
|
|
|
while (handler->ssrc_handler->csch.first_ts == 0) |
|
|
|
handler->ssrc_handler->csch.first_ts = ssl_random(); |
|
|
|
handler->ssrc_handler->rtp_mark = 1; |
|
|
|
|
|
|
|
ilogs(codec, LOG_DEBUG, "Created media playback context for " STR_FORMAT " -> " STR_FORMAT "", |
|
|
|
@ -1658,7 +1654,7 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa |
|
|
|
|| !h->dest_pt.codec_def) |
|
|
|
break; |
|
|
|
|
|
|
|
uint32_t ts_diff = packet_ts - ch->last_ts; |
|
|
|
uint32_t ts_diff = packet_ts - ch->csch.last_ts; |
|
|
|
|
|
|
|
// if packet TS is larger than last tracked TS, we can force the next packet if packets were lost and the TS |
|
|
|
// difference is too large. if packet TS is the same or lower (can happen for supplement codecs) we can wait |
|
|
|
@ -1681,20 +1677,20 @@ static int __handler_func_sequencer(struct media_packet *mp, struct transcode_pa |
|
|
|
} |
|
|
|
|
|
|
|
if (ch) { |
|
|
|
uint32_t ts_diff = ch->last_ts - packet->ts; |
|
|
|
uint32_t ts_diff = ch->csch.last_ts - packet->ts; |
|
|
|
if (ts_diff < 0x80000000) { // ch->last_ts >= packet->ts |
|
|
|
// multiple consecutive packets with same TS: this could be a compound packet, e.g. a large video frame, or |
|
|
|
// it could be a supplemental audio codec with static timestamps, in which case we adjust the TS forward |
|
|
|
// by one frame length. This is needed so that the next real audio packet (with real TS) is not mistakenly |
|
|
|
// seen as overdue |
|
|
|
if (h->source_pt.codec_def && h->source_pt.codec_def->supplemental) |
|
|
|
ch->last_ts += h->source_pt.clock_rate * (ch->ptime ?: 20) / 1000; |
|
|
|
ch->csch.last_ts += h->source_pt.clock_rate * (ch->ptime ?: 20) / 1000; |
|
|
|
} |
|
|
|
else |
|
|
|
ch->last_ts = packet->ts; |
|
|
|
ch->csch.last_ts = packet->ts; |
|
|
|
|
|
|
|
if (input_ch) |
|
|
|
input_ch->last_ts = ch->last_ts; |
|
|
|
input_ch->csch.last_ts = ch->csch.last_ts; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
@ -1751,8 +1747,8 @@ out_ch: |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void __output_rtp(struct media_packet *mp, struct codec_ssrc_handler *ch, |
|
|
|
struct codec_handler *handler, // normally == ch->handler except for DTMF |
|
|
|
void codec_output_rtp(struct media_packet *mp, struct codec_scheduler *csch, |
|
|
|
struct codec_handler *handler, |
|
|
|
char *buf, // malloc'd, room for rtp_header + filled-in payload |
|
|
|
unsigned int payload_len, |
|
|
|
unsigned long payload_ts, |
|
|
|
@ -1791,10 +1787,10 @@ static void __output_rtp(struct media_packet *mp, struct codec_ssrc_handler *ch, |
|
|
|
|
|
|
|
// this packet is dynamically allocated, so we're able to schedule it. |
|
|
|
// determine scheduled time to send |
|
|
|
if (ch->first_send.tv_sec && handler->dest_pt.clock_rate) { |
|
|
|
if (csch->first_send.tv_sec && handler->dest_pt.clock_rate) { |
|
|
|
// scale first_send from first_send_ts to ts |
|
|
|
p->ttq_entry.when = ch->first_send; |
|
|
|
uint32_t ts_diff = (uint32_t) ts - (uint32_t) ch->first_send_ts; // allow for wrap-around |
|
|
|
p->ttq_entry.when = csch->first_send; |
|
|
|
uint32_t ts_diff = (uint32_t) ts - (uint32_t) csch->first_send_ts; // allow for wrap-around |
|
|
|
ts_diff += ts_delay; |
|
|
|
long long ts_diff_us = |
|
|
|
(unsigned long long) ts_diff * 1000000 / handler->dest_pt.clock_rate; |
|
|
|
@ -1803,24 +1799,24 @@ static void __output_rtp(struct media_packet *mp, struct codec_ssrc_handler *ch, |
|
|
|
// how far in the future is this? |
|
|
|
ts_diff_us = timeval_diff(&p->ttq_entry.when, &rtpe_now); |
|
|
|
if (ts_diff_us > 1000000 || ts_diff_us < -1000000) // more than one second, can't be right |
|
|
|
ch->first_send.tv_sec = 0; // fix it up below |
|
|
|
csch->first_send.tv_sec = 0; // fix it up below |
|
|
|
} |
|
|
|
if (!ch->first_send.tv_sec || !p->ttq_entry.when.tv_sec) { |
|
|
|
p->ttq_entry.when = ch->first_send = rtpe_now; |
|
|
|
ch->first_send_ts = ts; |
|
|
|
if (!csch->first_send.tv_sec || !p->ttq_entry.when.tv_sec) { |
|
|
|
p->ttq_entry.when = csch->first_send = rtpe_now; |
|
|
|
csch->first_send_ts = ts; |
|
|
|
} |
|
|
|
|
|
|
|
long long ts_diff_us |
|
|
|
= timeval_diff(&p->ttq_entry.when, &rtpe_now); |
|
|
|
|
|
|
|
ch->output_skew = ch->output_skew * 15 / 16 + ts_diff_us / 16; |
|
|
|
if (ch->output_skew > 50000 && ts_diff_us > 10000) { // arbitrary value, 50 ms, 10 ms shift |
|
|
|
csch->output_skew = csch->output_skew * 15 / 16 + ts_diff_us / 16; |
|
|
|
if (csch->output_skew > 50000 && ts_diff_us > 10000) { // arbitrary value, 50 ms, 10 ms shift |
|
|
|
ilogs(transcoding, LOG_DEBUG, "Steady clock skew of %li.%01li ms detected, shifting send timer back by 10 ms", |
|
|
|
ch->output_skew / 1000, |
|
|
|
(ch->output_skew % 1000) / 100); |
|
|
|
csch->output_skew / 1000, |
|
|
|
(csch->output_skew % 1000) / 100); |
|
|
|
timeval_add_usec(&p->ttq_entry.when, -10000); |
|
|
|
ch->output_skew -= 10000; |
|
|
|
ch->first_send_ts += ch->encoder_format.clockrate / 100; |
|
|
|
csch->output_skew -= 10000; |
|
|
|
csch->first_send_ts += handler->dest_pt.clock_rate / 100; |
|
|
|
ts_diff_us = timeval_diff(&p->ttq_entry.when, &rtpe_now); |
|
|
|
} |
|
|
|
else if (ts_diff_us < 0) { |
|
|
|
@ -1829,8 +1825,8 @@ static void __output_rtp(struct media_packet *mp, struct codec_ssrc_handler *ch, |
|
|
|
ts_diff_us / 1000, |
|
|
|
(ts_diff_us % 1000) / 100); |
|
|
|
timeval_add_usec(&p->ttq_entry.when, ts_diff_us); |
|
|
|
ch->output_skew += ts_diff_us; |
|
|
|
ch->first_send_ts -= (long long) ch->encoder_format.clockrate * ts_diff_us / 1000000; |
|
|
|
csch->output_skew += ts_diff_us; |
|
|
|
csch->first_send_ts -= (long long) handler->dest_pt.clock_rate * ts_diff_us / 1000000; |
|
|
|
ts_diff_us = timeval_diff(&p->ttq_entry.when, &rtpe_now); // should be 0 now |
|
|
|
} |
|
|
|
|
|
|
|
@ -1882,12 +1878,7 @@ static int codec_add_dtmf_packet(struct codec_ssrc_handler *ch, struct codec_ssr |
|
|
|
if (G_UNLIKELY(!output_ch->encoder)) |
|
|
|
goto skip; |
|
|
|
|
|
|
|
// init some vars |
|
|
|
ch->first_ts = output_ch->first_ts; |
|
|
|
ch->first_send_ts = output_ch->first_send_ts; |
|
|
|
ch->output_skew = output_ch->output_skew; |
|
|
|
ch->first_send = output_ch->first_send; |
|
|
|
|
|
|
|
ch->csch = output_ch->csch; |
|
|
|
|
|
|
|
// the correct output TS is the encoder's FIFO PTS at the start of the DTMF |
|
|
|
// event. however, we must shift the FIFO PTS forward as the DTMF event goes on |
|
|
|
@ -1903,7 +1894,7 @@ static int codec_add_dtmf_packet(struct codec_ssrc_handler *ch, struct codec_ssr |
|
|
|
// roll back TS to start of event |
|
|
|
ts -= ch->last_dtmf_event_ts; |
|
|
|
// adjust to output RTP TS |
|
|
|
unsigned long packet_ts = ts + output_ch->first_ts; |
|
|
|
unsigned long packet_ts = ts + output_ch->csch.first_ts; |
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Scaling DTMF packet timestamp and duration: TS %lu -> %lu " |
|
|
|
"(%u -> %u)", |
|
|
|
@ -1937,10 +1928,10 @@ skip: |
|
|
|
char *buf = malloc(packet->payload->len + sizeof(struct rtp_header) + RTP_BUFFER_TAIL_ROOM); |
|
|
|
memcpy(buf + sizeof(struct rtp_header), packet->payload->s, packet->payload->len); |
|
|
|
if (packet->bypass_seq) // inject original seq |
|
|
|
__output_rtp(mp, ch, packet->handler ? : h, buf, packet->payload->len, packet->ts, |
|
|
|
codec_output_rtp(mp, &ch->csch, packet->handler ? : h, buf, packet->payload->len, packet->ts, |
|
|
|
packet->marker, packet->p.seq, -1, payload_type, ts_delay); |
|
|
|
else // use our own sequencing |
|
|
|
__output_rtp(mp, ch, packet->handler ? : h, buf, packet->payload->len, packet->ts, |
|
|
|
codec_output_rtp(mp, &ch->csch, packet->handler ? : h, buf, packet->payload->len, packet->ts, |
|
|
|
packet->marker, -1, 0, payload_type, ts_delay); |
|
|
|
mp->ssrc_out->parent->seq_diff++; |
|
|
|
|
|
|
|
@ -2293,7 +2284,7 @@ void codec_add_dtmf_event(struct codec_ssrc_handler *ch, int code, int level, ui |
|
|
|
ilogs(transcoding, LOG_DEBUG, "DTMF event state change: code %i, volume %i, TS %lu", |
|
|
|
new_ev.code, new_ev.volume, (unsigned long) ts); |
|
|
|
dtmf_dsp_event(&new_ev, &ch->dtmf_state, ch->handler->media, ch->handler->source_pt.clock_rate, |
|
|
|
ts + ch->first_ts); |
|
|
|
ts + ch->csch.first_ts); |
|
|
|
|
|
|
|
// add to queue if we're doing PCM -> DTMF event conversion |
|
|
|
// this does not capture events when doing DTMF delay (dtmf_payload_type == -1) |
|
|
|
@ -3506,17 +3497,14 @@ static void __free_ssrc_handler(void *chp) { |
|
|
|
dtx_buffer_stop(&ch->dtx_buffer); |
|
|
|
} |
|
|
|
|
|
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) { |
|
|
|
struct codec_ssrc_handler *ch = u1; |
|
|
|
struct media_packet *mp = u2; |
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "RTP media successfully encoded: TS %llu, len %i", |
|
|
|
(unsigned long long) enc->avpkt->pts, enc->avpkt->size); |
|
|
|
|
|
|
|
// run this through our packetizer |
|
|
|
void packet_encoded_packetize(encoder_t *enc, struct codec_ssrc_handler *ch, struct media_packet *mp, |
|
|
|
void (*fn)(encoder_t *, struct codec_ssrc_handler *, struct media_packet *, str *, |
|
|
|
char *, unsigned int)) |
|
|
|
{ |
|
|
|
AVPacket *in_pkt = enc->avpkt; |
|
|
|
|
|
|
|
while (1) { |
|
|
|
while (true) { |
|
|
|
// figure out how big of a buffer we need |
|
|
|
unsigned int payload_len = MAX(MAX(enc->avpkt->size, ch->bytes_per_packet), |
|
|
|
sizeof(struct telephone_event_payload)); |
|
|
|
@ -3541,46 +3529,7 @@ static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) { |
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "Received packet of %zu bytes from packetizer", inout.len); |
|
|
|
|
|
|
|
// check special payloads |
|
|
|
|
|
|
|
unsigned int repeats = 0; |
|
|
|
int payload_type = -1; |
|
|
|
int dtmf_pt = ch->handler->dtmf_payload_type; |
|
|
|
if (dtmf_pt == -1) |
|
|
|
dtmf_pt = ch->handler->real_dtmf_payload_type; |
|
|
|
int is_dtmf = 0; |
|
|
|
|
|
|
|
if (dtmf_pt != -1) |
|
|
|
is_dtmf = dtmf_event_payload(&inout, (uint64_t *) &enc->avpkt->pts, enc->avpkt->duration, |
|
|
|
&ch->dtmf_event, &ch->dtmf_events); |
|
|
|
if (is_dtmf) { |
|
|
|
payload_type = dtmf_pt; |
|
|
|
if (is_dtmf == 1) |
|
|
|
ch->rtp_mark = 1; // DTMF start event |
|
|
|
else if (is_dtmf == 3) |
|
|
|
repeats = 2; // DTMF end event |
|
|
|
} |
|
|
|
else { |
|
|
|
if (is_silence_event(&inout, &ch->silence_events, enc->avpkt->pts, enc->avpkt->duration)) |
|
|
|
payload_type = ch->handler->cn_payload_type; |
|
|
|
} |
|
|
|
|
|
|
|
// ready to send |
|
|
|
|
|
|
|
do { |
|
|
|
char *send_buf = buf; |
|
|
|
if (repeats > 0) { |
|
|
|
// need to duplicate the payload as __output_rtp consumes it |
|
|
|
send_buf = malloc(pkt_len); |
|
|
|
memcpy(send_buf, buf, pkt_len); |
|
|
|
} |
|
|
|
__output_rtp(mp, ch, ch->handler, send_buf, inout.len, ch->first_ts |
|
|
|
+ fraction_divl(enc->avpkt->pts, &enc->clockrate_fact), |
|
|
|
ch->rtp_mark ? 1 : 0, -1, 0, |
|
|
|
payload_type, 0); |
|
|
|
mp->ssrc_out->parent->seq_diff++; |
|
|
|
ch->rtp_mark = 0; |
|
|
|
} while (repeats--); |
|
|
|
fn(enc, ch, mp, &inout, buf, pkt_len); |
|
|
|
|
|
|
|
if (ret == 0) { |
|
|
|
// no more to go |
|
|
|
@ -3590,10 +3539,72 @@ static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) { |
|
|
|
// loop around and get more |
|
|
|
in_pkt = NULL; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void packet_encoded_tx(encoder_t *enc, struct codec_ssrc_handler *ch, struct media_packet *mp, |
|
|
|
str *inout, char *buf, unsigned int pkt_len); |
|
|
|
|
|
|
|
static int packet_encoded_rtp(encoder_t *enc, void *u1, void *u2) { |
|
|
|
struct codec_ssrc_handler *ch = u1; |
|
|
|
struct media_packet *mp = u2; |
|
|
|
|
|
|
|
ilogs(transcoding, LOG_DEBUG, "RTP media successfully encoded: TS %llu, len %i", |
|
|
|
(unsigned long long) enc->avpkt->pts, enc->avpkt->size); |
|
|
|
|
|
|
|
// run this through our packetizer |
|
|
|
packet_encoded_packetize(enc, ch, mp, packet_encoded_tx); |
|
|
|
|
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
static void packet_encoded_tx(encoder_t *enc, struct codec_ssrc_handler *ch, struct media_packet *mp, |
|
|
|
str *inout, char *buf, unsigned int pkt_len) |
|
|
|
{ |
|
|
|
// check special payloads |
|
|
|
|
|
|
|
unsigned int repeats = 0; |
|
|
|
int payload_type = -1; |
|
|
|
int dtmf_pt = ch->handler->dtmf_payload_type; |
|
|
|
if (dtmf_pt == -1) |
|
|
|
dtmf_pt = ch->handler->real_dtmf_payload_type; |
|
|
|
int is_dtmf = 0; |
|
|
|
|
|
|
|
if (dtmf_pt != -1) |
|
|
|
is_dtmf = dtmf_event_payload(inout, (uint64_t *) &enc->avpkt->pts, enc->avpkt->duration, |
|
|
|
&ch->dtmf_event, &ch->dtmf_events); |
|
|
|
if (is_dtmf) { |
|
|
|
payload_type = dtmf_pt; |
|
|
|
if (is_dtmf == 1) |
|
|
|
ch->rtp_mark = 1; // DTMF start event |
|
|
|
else if (is_dtmf == 3) |
|
|
|
repeats = 2; // DTMF end event |
|
|
|
} |
|
|
|
else { |
|
|
|
if (is_silence_event(inout, &ch->silence_events, enc->avpkt->pts, enc->avpkt->duration)) |
|
|
|
payload_type = ch->handler->cn_payload_type; |
|
|
|
} |
|
|
|
|
|
|
|
// ready to send |
|
|
|
|
|
|
|
do { |
|
|
|
char *send_buf = buf; |
|
|
|
if (repeats > 0) { |
|
|
|
// need to duplicate the payload as codec_output_rtp consumes it |
|
|
|
send_buf = malloc(pkt_len); |
|
|
|
memcpy(send_buf, buf, pkt_len); |
|
|
|
} |
|
|
|
codec_output_rtp(mp, &ch->csch, ch->handler, send_buf, inout->len, ch->csch.first_ts |
|
|
|
+ fraction_divl(enc->avpkt->pts, &enc->clockrate_fact), |
|
|
|
ch->rtp_mark ? 1 : 0, -1, 0, |
|
|
|
payload_type, 0); |
|
|
|
mp->ssrc_out->parent->seq_diff++; |
|
|
|
ch->rtp_mark = 0; |
|
|
|
} while (repeats--); |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void __dtmf_detect(struct codec_ssrc_handler *ch, AVFrame *frame) { |
|
|
|
if (!ch->dtmf_dsp) |
|
|
|
return; |
|
|
|
@ -3649,13 +3660,13 @@ static int packet_decoded_common(decoder_t *decoder, AVFrame *frame, void *u1, v |
|
|
|
struct codec_ssrc_handler *new_ch = __output_ssrc_handler(ch, mp); |
|
|
|
if (new_ch != ch) { |
|
|
|
// copy some essential parameters |
|
|
|
if (!new_ch->first_ts) |
|
|
|
new_ch->first_ts = ch->first_ts; |
|
|
|
if (!new_ch->csch.first_ts) |
|
|
|
new_ch->csch.first_ts = ch->csch.first_ts; |
|
|
|
|
|
|
|
if (decoder->def->supplemental) { |
|
|
|
// supp codecs return bogus timestamps. Adjust the frame's TS to be in |
|
|
|
// line with the primary decoder |
|
|
|
frame->pts -= new_ch->first_ts; |
|
|
|
frame->pts -= new_ch->csch.first_ts; |
|
|
|
} |
|
|
|
|
|
|
|
ch = new_ch; |
|
|
|
@ -3693,7 +3704,7 @@ static int packet_decoded_common(decoder_t *decoder, AVFrame *frame, void *u1, v |
|
|
|
if (mp->media_out) |
|
|
|
ch->encoder->callback = mp->media_out->encoder_callback; |
|
|
|
|
|
|
|
uint32_t ts = frame->pts + ch->first_ts; |
|
|
|
uint32_t ts = frame->pts + ch->csch.first_ts; |
|
|
|
__buffer_delay_frame(h->input_handler ? h->input_handler->delay_buffer : h->delay_buffer, |
|
|
|
ch, input_func, frame, mp, ts); |
|
|
|
frame = NULL; // consumed |
|
|
|
@ -3728,8 +3739,8 @@ static int packet_decode(struct codec_ssrc_handler *ch, struct codec_ssrc_handle |
|
|
|
{ |
|
|
|
int ret = 0; |
|
|
|
|
|
|
|
if (!ch->first_ts) |
|
|
|
ch->first_ts = packet->ts; |
|
|
|
if (!ch->csch.first_ts) |
|
|
|
ch->csch.first_ts = packet->ts; |
|
|
|
|
|
|
|
if (ch->decoder->def->dtmf) { |
|
|
|
if (packet_dtmf_event(ch, input_ch, packet, mp)) |
|
|
|
|