📄 source.c
字号:
if (psf == NULL) {
fprintf(stderr, "Could not open playout.log\n");
} else {
atexit(source_close_log);
fprintf(psf, "# <SSRC> <RTP timestamp> <talkstart> <jitter> <transit> <avg transit> <last transit> <playout del> <spike_var> <arr time>\n");
}
t0 = ts - 1000; /* -1000 in case of out of order first packet */
}
fprintf(psf, "0x%08x %.6f %5u %5u %5u %5u %5u %5u %5u %5u\n",
src->pdbe->ssrc,
(ts - t0)/8000.0,
timestamp_to_ms(src->talkstart),
timestamp_to_ms(src->pdbe->jitter),
timestamp_to_ms(src->pdbe->transit),
timestamp_to_ms(src->pdbe->avg_transit),
timestamp_to_ms(src->pdbe->last_transit),
timestamp_to_ms(src->pdbe->playout),
timestamp_to_ms(src->spike_var),
timestamp_to_ms(now)
);
source_validate(src);
}
#endif /* SOURCE_LOG_PLAYOUT */
static void
source_update_toged(source *src, int toged)
{
source_validate(src);
src->toged_mask <<= 1;
src->toged_mask |= toged;
src->toged_cont = 0;
if (toged == 1) {
int m;
m = src->toged_mask & 0xff; /* Last 8 packets */
while (m) {
src->toged_cont += (m & 1);
m >>= 1;
}
}
source_validate(src);
}
static void
sanity_check_playout_time(timestamp_t now, timestamp_t playout)
{
assert(ts_valid(now));
assert(ts_valid(playout));
/* Check that the calculated playout time is within 10 seconds */
/* of the current time. This is an arbitrary check, but if it */
/* fails something has almost certainly gone wrong... */
assert(timestamp_to_ms(ts_abs_diff(now, playout)) < 10000);
}
static void
source_process_packets(session_t *sp, source *src, timestamp_t now)
{
/* This function calculates the desired playout point for each packet and */
/* inserts it into the channel decoder input buffer (src->channel) at the */
/* correct time interval. */
timestamp_t src_ts, playout, transit;
pdb_entry_t *e;
rtp_packet *p;
cc_id_t ccid = -1;
uint16_t units_per_packet = -1;
uint32_t delta_ts, delta_seq;
uint8_t codec_pt;
uint8_t adjust_playout;
source_validate(src);
e = src->pdbe;
/* Timing of startup is such that sometimes we get huge burst of packets */
/* between source creation and first round of packet processing. Causes */
/* too much audio to be buffered and skew adjustment make lots of adjust */
/* actions unnecessarily. */
if (src->packets_done == 0) {
int16_t discarded = 0;
while(pktbuf_get_count(src->pktbuf) > 1) {
pktbuf_dequeue(src->pktbuf, &p);
discarded++;
xfree(p);
}
if (discarded > 0) {
debug_msg("Discarded %d surplus packets\n", discarded);
}
}
/* Loop for each new packet we have received... */
while(pktbuf_dequeue(src->pktbuf, &p)) {
adjust_playout = FALSE;
ccid = channel_coder_get_by_payload((u_char)p->pt);
if (channel_verify_and_stat(ccid, (u_char)p->pt, p->data, p->data_len, &units_per_packet, &codec_pt) == FALSE) {
debug_msg("Packet discarded for ssrc 0x%08lx: packet failed channel verify.\n", e->ssrc);
xfree(p);
continue;
}
if (e->channel_coder_id != ccid ||
e->enc != codec_pt ||
e->units_per_packet != units_per_packet ||
src->packets_done == 0) {
/* Either the channel coder, payload type or number of units */
/* per packet has changed (or this is the first packet from */
/* this source, and so these have not been initialized). We */
/* reconfigure the source and update the user interface... */
const audio_format *dev_fmt = audio_get_ofmt(sp->audio_device);
channel_describe_data(ccid, codec_pt, p->data, p->data_len, src->pdbe->enc_fmt, src->pdbe->enc_fmt_len);
source_reconfigure(src, ccid, codec_pt, units_per_packet, sp->converter, sp->render_3d,
(uint32_t)dev_fmt->sample_rate,
(uint16_t)dev_fmt->channels);
if (sp->mbus_engine) {
ui_send_stats(sp, sp->mbus_ui_addr, src->pdbe->ssrc);
}
adjust_playout = TRUE;
}
/* We have a heap of conditions to check before we get to the */
/* playout calculation. These are primarily to detect whether */
/* we have a new talkspurt as indicated by marker bit, or an */
/* implicit new talkspurt indicated by change in relationship */
/* between timestamps or sequence numbers, or whether the */
/* config has changed at the receiver or sender. */
/* */
/* We also have to check for "spikes" in packet arrivals as we */
/* do not want to consider these packets in the playout */
/* calculation. */
/* Marker bit set: explicit indication of new talkspurt */
if (p->m) {
adjust_playout = TRUE;
debug_msg("Adjusting playout: marker bit set\n");
}
/* Check for change in timestamp-sequence number relationship. */
/* This is an implicit indication of a new talkspurt (e.g. if */
/* the packet containing the marker bit was lost. */
delta_seq = p->seq - e->last_seq;
delta_ts = p->ts - e->last_ts;
if (delta_seq * e->inter_pkt_gap != delta_ts) {
debug_msg("Adjusting playout: sequence number/timestamp realignment\n");
adjust_playout = TRUE;
}
/* transit is difference between our clock and their */
/* clock. Note, we have to put through sequencer */
/* because our time representation is shorter than */
/* RTP's 32bits. Mapping use first order differences */
/* to update time representation */
src_ts = ts_seq32_in(&e->seq, e->sample_rate, p->ts);
transit = ts_sub(now, src_ts);
if (src->packets_done == 0 || ts_gt(ts_abs_diff(transit, e->transit), transit_jump)) {
/* Need a fresh transit estimate */
debug_msg("Transit estimate reset %s\n", (src->packets_done == 0)?"(first packet)":"");
e->transit = e->last_transit = e->last_last_transit = transit;
e->avg_transit = transit;
adjust_playout = TRUE;
}
/* Check neither we nor source has changed sampling rate */
if (ts_get_freq(transit) != ts_get_freq(e->last_transit)) {
debug_msg("Adjusting playout: sampling rate change (either local or remote)\n");
adjust_playout = TRUE;
e->received = 0;
}
/* Spike adaptation - Ramjee, Kurose, Towsley, and Schulzerinne. */
/* Adaptive Playout Mechanisms for Packetized Audio Applications */
/* in Wide-Area Networks, IEEE Infocom 1994, pp 680-688. */
if (adjust_playout) {
/* If we're about to adjust the playout point, we ignore spike events... */
if (src->playout_mode == PLAYOUT_MODE_SPIKE) {
debug_msg("Leaving spike mode due to required playout adjustment\n");
}
src->playout_mode = PLAYOUT_MODE_NORMAL;
} else {
/* ...otherwise, we track spikes in the transit delay. */
timestamp_t delta_transit = ts_abs_diff(transit, e->last_transit);
if (ts_gt(delta_transit, spike_jump)) {
/* Transit delay increased suddenly - this is a "spike" */
debug_msg("Entering spike mode (%d, %dHz) > (%d, %dHz))\n",
delta_transit.ticks, ts_get_freq(delta_transit),
spike_jump.ticks, ts_get_freq(spike_jump));
debug_msg("transit (%d, %dHz) last_transit (%d, %dHz)\n",
transit.ticks, ts_get_freq(transit),
e->last_transit.ticks, ts_get_freq(e->last_transit));
src->playout_mode = PLAYOUT_MODE_SPIKE;
src->spike_var = zero_ts;
e->spike_events++;
} else {
if (src->playout_mode == PLAYOUT_MODE_SPIKE) {
timestamp_t delta_var;
src->spike_var = ts_div(src->spike_var, 2);
delta_var = ts_add(ts_abs_diff(transit, e->last_transit),
ts_abs_diff(transit, e->last_last_transit));
delta_var = ts_div(delta_var, 8);
src->spike_var = ts_add(src->spike_var, delta_var);
if (ts_gt(spike_end, src->spike_var)) {
debug_msg("Leaving spike mode\n");
src->playout_mode = PLAYOUT_MODE_NORMAL;
}
}
}
}
/* Check for continuous number of packets being discarded. */
/* This happens when jitter or transit estimate is no longer */
/* consistent with the real world. */
if (src->toged_cont >= NO_TOGED_CONT_FOR_PLAYOUT_RECALC) {
debug_msg("Adjusting playout: many consecutive discarded packets\n");
adjust_playout = TRUE;
src->toged_cont = 0;
/* We've been dropping packets so take a new transit */
/* estimate and discard all existing transit info. */
e->transit = e->last_transit = e->last_last_transit = transit;
e->avg_transit = transit;
}
if (adjust_playout && (ts_gt(ts_sub(now, e->last_arr), transit_reset) || (e->received < 20))) {
/* Source has been quiet for a long time. Discard */
/* old average transit estimate. */
debug_msg("Average transit reset (%d -> %d)\n", timestamp_to_ms(transit), timestamp_to_ms(e->avg_transit));
e->transit = transit;
e->last_transit = transit;
e->last_last_transit = transit;
e->avg_transit = transit;
}
/* Calculate the playout point for this packet. */
/* Playout calc updates avg_transit and jitter. */
/* Do not call if in spike mode as it distorts both. */
if (src->playout_mode == PLAYOUT_MODE_NORMAL) {
playout = playout_calc(sp, e->ssrc, transit, adjust_playout);
} else {
playout = e->playout;
debug_msg("in spike\n");
}
playout = ts_add(e->transit, playout);
playout = ts_add(src_ts, playout);
debug_msg("%d %d\n", timestamp_to_ms(playout), timestamp_to_ms(now));
sanity_check_playout_time(now, playout);
/* At this point we know the desired playout time for this packet, */
/* and adjust_playout is set if this has changed from the previous */
/* packet. */
if (adjust_playout) {
if (ts_gt(playout, now) == FALSE) {
/* This is the first packet in this spurt and */
/* it would not have been played out. Push */
/* back to point where it will... */
/* This usually happens because of VAD check */
/* above... */
timestamp_t shortfall = ts_sub(now, playout);
/* And then a little more... */
shortfall = ts_add(shortfall, e->frame_dur);
e->playout = ts_add(e->playout, shortfall);
playout = ts_add(playout, shortfall);
debug_msg("Pushed back first packet - would have missed playout time\n");
assert(ts_gt(playout, now));
}
if (ts_valid(src->next_played) && ts_gt(src->next_played, playout)) {
/* Talkspurts would have overlapped. May */
/* cause problems for redundancy decoder. */
/* Don't take any chances. */
timestamp_t overlap = ts_sub(src->next_played, playout);
debug_msg("Overlap %d us (next_played %d (%dhz) playout %d (%dHz))\n",
timestamp_to_us(overlap),
src->next_played.ticks, ts_get_freq(src->next_played),
playout.ticks, ts_get_freq(playout));
e->playout = ts_add(e->playout, overlap);
playout = ts_add(playout, overlap);
}
src->talkstart = playout; /* Note start of new talkspurt */
src->post_talkstart_units = 0;
} else {
src->post_talkstart_units++;
}
if (src->packets_done == 0) {
/* This is first packet so expect next played to have its */
/* playout. */
src->next_played = playout;
}
sanity_check_playout_time(now, playout);
if (ts_gt(now, playout)) {
/* Packet being decoded is before start of current */
/* so there is now way it's audio will be played */
/* Playout recalculation gets triggered in */
/* rtp_callback if toged_cont hits a critical */
/* threshold. It signifies current playout delay */
/* is inappropriate. */
if (src->playout_mode == PLAYOUT_MODE_NORMAL) {
debug_msg("Packet late (compared to now)\n");
source_update_toged(src, 1);
src->pdbe->jit_toged++;
} else {
/* Spike mode - don't worry about jit_toged */
src->pdbe->spike_toged++;
}
} else {
/* This packet arrived in time to be played out. We */
/* add it to the channel decoder buffer at the point */
/* determined by the playout delay. */
u_char *u = (u_char*)block_alloc(p->data_len);
memcpy(u, p->data, p->data_len);
if (source_process_packet(src, u, p->data_len, codec_pt, playout) == FALSE) {
debug_msg("Unwanted packet?\n");
block_free(u, (int)p->data_len);
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -