static void pb_validate(pb_t *pb) { #ifdef DEBUG pb_node_t *stop, *curr; uint32_t cnt = 0; stop = pb->psentinel; curr = pb->psentinel->prev; while (curr != stop) { assert(curr->magic == PB_NODE_MAGIC); assert(curr->data != NULL); assert(curr->data_len > 0); assert(curr->next->prev == curr); assert(curr->prev->next == curr); if (curr->next != stop) assert(ts_gt(curr->next->playout, curr->playout)); if (curr->prev != stop) assert(ts_gt(curr->playout, curr->prev->playout)); curr = curr->prev; cnt++; } assert(pb->n_nodes == cnt); assert(pb->n_iterators < PB_MAX_ITERATORS); for (cnt = 0; cnt < pb->n_iterators; cnt ++) { assert(pb->iterators[cnt].buffer == pb); } #endif assert(pb->magic == PB_MAGIC); }
int layered_decoder_decode(u_char *state, struct s_pb *in, struct s_pb *out, timestamp_t now) { struct s_pb_iterator *pi; u_char *c_get; channel_data *c; uint32_t clen; timestamp_t playout; UNUSED(state); pb_iterator_create(in, &pi); assert(pi != NULL); while(pb_iterator_get_at(pi, &c_get, &clen, &playout)) { c = (channel_data*)c_get; assert(c != NULL); assert(clen == sizeof(channel_data)); if (ts_gt(playout, now)) { /* Playout point of unit is after now. Stop! */ break; } pb_iterator_detach_at(pi, &c_get, &clen, &playout); layered_decoder_reorganise(c, out, playout); } pb_iterator_destroy(in, &pi); return TRUE; }
int redundancy_decoder_decode(u_char *state, struct s_pb *in, struct s_pb *out, timestamp_t now) { struct s_pb_iterator *pi; u_char *c_get; channel_data *c; uint32_t clen; timestamp_t cplayout; pb_iterator_create(in, &pi); assert(pi != NULL); assert(state == NULL); /* No decoder state necesssary */ UNUSED(state); while(pb_iterator_get_at(pi, &c_get, &clen, &cplayout)) { c = (channel_data*)c_get; assert(c != NULL); assert(clen == sizeof(channel_data)); if (ts_gt(cplayout, now)) { break; } pb_iterator_detach_at(pi, &c_get, &clen, &cplayout); c = (channel_data*)c_get; assert(c->nelem == 1); redundancy_decoder_output(c->elem[0], out, cplayout); channel_data_destroy(&c, sizeof(channel_data)); } pb_iterator_destroy(in, &pi); return TRUE; }
static media_data * red_media_data_create_or_get(struct s_pb *p, timestamp_t playout) { struct s_pb_iterator *pi; u_char *md_get; media_data *md; uint32_t md_len, success; timestamp_t md_playout; pb_iterator_create(p, &pi); /* iterator is attached to sentinel - can move back or forwards */ while(pb_iterator_retreat(pi)) { success = pb_iterator_get_at(pi, &md_get, &md_len, &md_playout); md = (media_data*)md_get; assert(success); if (ts_eq(md_playout, playout)) { goto done; } else if (ts_gt(playout, md_playout)) { /* we have gone too far back */ break; } } /* Not found in playout buffer */ media_data_create(&md, 0); success = pb_add(p, (u_char*)md, sizeof(media_data), playout); assert(success); done: pb_iterator_destroy(p, &pi); return md; }
timestamp_t playout_calc(session_t *sp, uint32_t ssrc, timestamp_t transit, int new_spurt) /*****************************************************************************/ /* The primary purpose of this function is to calculate the playout point */ /* for new talkspurts (new_spurt). It also maintains the jitter and transit */ /* time estimates from the source to us. The value returned is the local */ /* playout time. */ /*****************************************************************************/ { timestamp_t delta_transit; pdb_entry_t *e; pdb_item_get(sp->pdb, ssrc, &e); assert(e != NULL); delta_transit = ts_abs_diff(transit, e->avg_transit); if (ts_gt(transit, e->avg_transit)) { e->avg_transit = ts_add(e->avg_transit, ts_div(delta_transit,16)); } else { e->avg_transit = ts_sub(e->avg_transit, ts_div(delta_transit,16)); } if (new_spurt == TRUE) { timestamp_t hvar, jvar; /* Host and jitter components */ debug_msg("New talkspurt\n"); hvar = playout_constraints_component(sp, e); jvar = ts_mul(e->jitter, PLAYOUT_JITTER_SCALE); if (ts_gt(hvar, jvar)) { e->playout = hvar; } else { e->playout = jvar; } e->transit = e->avg_transit; } else { /* delta_transit is abs((s[j+1] - d[j+1]) - (s[j] - d[j])) */ delta_transit = ts_abs_diff(transit, e->last_transit); /* Update jitter estimate using */ /* jitter = (7/8)jitter + (1/8) new_jitter */ e->jitter = ts_mul(e->jitter, 7); e->jitter = ts_add(e->jitter, delta_transit); e->jitter = ts_div(e->jitter, 8); } e->last_transit = transit; return e->playout; }
int pb_relevant (struct s_pb *pb, timestamp_t now) { pb_node_t *last; last = pb->psentinel->prev; /* tail */ if (last == pb->psentinel || ts_gt(now, last->playout)) { return FALSE; } return TRUE; }
void pb_shift_units_back_after(pb_t *pb, timestamp_t ref_ts, timestamp_t delta) { pb_node_t *stop, *curr; pb_validate(pb); stop = pb->psentinel; curr = pb->psentinel->prev; while(curr != stop && ts_gt(curr->playout, ref_ts)) { curr->playout = ts_add(curr->playout, delta); curr = curr->prev; } pb_validate(pb); }
int pb_iterator_audit(pb_iterator_t *pi, timestamp_t history_len) { timestamp_t cutoff; int removed; pb_node_t *stop, *curr, *next; pb_t *pb; #ifdef DEBUG /* If we are debugging we check we are not deleting * nodes pointed to by other iterators since this *BAD* */ uint16_t i, n_iterators; pb_iterator_t *iterators = pi->buffer->iterators; n_iterators = pi->buffer->n_iterators; #endif pb_validate(pi->buffer); pb = pi->buffer; stop = pi->node; removed = 0; if (pi->node != pb->psentinel) { curr = pb->psentinel->next; /* head */; cutoff = ts_sub(pi->node->playout, history_len); while(ts_gt(cutoff, curr->playout)) { /* About to erase a block an iterator is using! */ #ifdef DEBUG for(i = 0; i < n_iterators; i++) { assert(iterators[i].node != curr); } #endif next = curr->next; curr->next->prev = curr->prev; curr->prev->next = curr->next; pb->freeproc(&curr->data, curr->data_len); pb->n_nodes--; block_free(curr, sizeof(pb_node_t)); curr = next; removed ++; } } return removed; }
int vanilla_decoder_decode(u_char *state, struct s_pb *in, struct s_pb *out, timestamp_t now) { struct s_pb_iterator *pi; channel_unit *cu; u_char *c_get; channel_data *c; uint32_t clen; timestamp_t playout; assert(state == NULL); /* No decoder state needed */ UNUSED(state); pb_iterator_create(in, &pi); assert(pi != NULL); while(pb_iterator_get_at(pi, &c_get, &clen, &playout)) { c = (channel_data*)c_get; assert(c != NULL); assert(clen == sizeof(channel_data)); if (ts_gt(playout, now)) { /* Playout point of unit is after now. Stop! */ break; } pb_iterator_detach_at(pi, &c_get, &clen, &playout); c = (channel_data*)c_get; assert(c != NULL); assert(c->nelem == 1); cu = c->elem[0]; vanilla_decoder_output(cu, out, playout); channel_data_destroy(&c, sizeof(channel_data)); } pb_iterator_destroy(in, &pi); return TRUE; }
int pb_add (pb_t *pb, u_char *data, uint32_t data_len, timestamp_t playout) { pb_node_t *curr, *stop, *made; assert(data != NULL); assert(data_len > 0); pb_validate(pb); /* Assuming that addition will be at the end of list (or near it) */ stop = pb->psentinel; curr = stop->prev; /* list tail */ while (curr != stop && ts_gt(curr->playout, playout)) { curr = curr->prev; } /* Check if unit already exists */ if (curr != stop && ts_eq(curr->playout, playout)) { debug_msg("Add failed - unit already exists\n"); return FALSE; } made = (pb_node_t*)block_alloc(sizeof(pb_node_t)); if (made) { made->playout = playout; made->data = data; made->data_len = data_len; made->prev = curr; made->next = curr->next; made->next->prev = made; made->prev->next = made; made->magic = PB_NODE_MAGIC; pb->n_nodes++; pb_validate(pb); return TRUE; } debug_msg("Insufficient memory\n"); return FALSE; }
int redundancy_encoder_encode (u_char *state, struct s_pb *in, struct s_pb *out, uint32_t upp) { uint32_t m_len; timestamp_t playout; struct s_pb_iterator *pi; u_char *m_get; media_data *m; red_enc_state *re = (red_enc_state*)state; assert(upp != 0 && upp <= MAX_UNITS_PER_PACKET); pb_iterator_create(in, &pi); assert(pi != NULL); pb_iterator_advance(pi); while(pb_iterator_detach_at(pi, &m_get, &m_len, &playout)) { m = (media_data*)m_get; /* Remove element from playout buffer - it belongs to * the redundancy encoder now. */ #ifdef DEBUG_REDUNDANCY debug_msg("claimed %d, prev %d\n", playout.ticks, re->last_in.ticks); #endif /* DEBUG_REDUNDANCY */ assert(m != NULL); if (re->units_ready == 0) { re->last_in = playout; re->last_in.ticks--; } assert(ts_gt(playout, re->last_in)); re->last_in = playout; if (m->nrep > 0) { pb_add(re->media_buffer, (u_char*)m, m_len, playout); re->units_ready++; } else { /* Incoming unit has no data so transmission is * not happening. */ #ifdef DEBUG_REDUNDANCY debug_msg("No incoming data\n"); #endif /* DEBUG_REDUNDANCY */ media_data_destroy(&m, sizeof(media_data)); pb_flush(re->media_buffer); re->units_ready = 0; continue; } if (re->units_ready && (re->units_ready % upp) == 0) { channel_data *cd; int s; cd = redundancy_encoder_output(re, upp); assert(cd != NULL); s = pb_add(out, (u_char*)cd, sizeof(channel_data), playout); #ifdef DEBUG_REDUNDANCY debug_msg("Ready %d, Added %d\n", re->units_ready, playout.ticks); #endif /* DEBUG_REDUNDANCY */ assert(s); } } pb_iterator_destroy(in, &pi); return TRUE; }