static int place_unit(media_data *md, coded_unit *cu) { int16_t i; #ifdef DEBUG_REDUNDANCY const codec_format_t *cf; cf = codec_get_format(cu->id); debug_msg("%d %s\n", md->nrep, cf->long_name); #endif /* DEBUG_REDUNDANCY */ assert(md->nrep < MAX_MEDIA_UNITS); for (i = 0; i < md->nrep; i++) { if (md->rep[i]->id == cu->id) { return FALSE; } } if (md->nrep > 0 && codec_is_native_coding(md->rep[md->nrep - 1]->id)) { /* Buffer shifts can mean redundancy is received after primary decoded. */ /* Just discard. i.e. pkt 1 (t1 t0) pkt2 (t2 t1), if pkt2 arrives after */ /* pkt1 decoded we don't want to append redundant t1 data as it confuses */ /* decoder. */ /* XXX Should check for packet re-ordering i.e. pkt2 arrives and is */ /* decoded before pkt 1 then should use pkt 1's data as this will be */ /* higher quality under normal circumstances. */ return FALSE; } md->rep[md->nrep] = cu; md->nrep++; return TRUE; }
int codec_encode(codec_state *cs, coded_unit *in_native, coded_unit *cu) { uint16_t ifs, fmt; int success; assert(cs != NULL); assert(in_native != NULL); assert(cu != NULL); assert(codec_is_native_coding(in_native->id)); assert (in_native->state == NULL); #ifdef DEBUG { const codec_format_t *cf = codec_get_format(cs->id); assert (cf->format.bytes_per_block == in_native->data_len); } #endif cu->id = cs->id; ifs = CODEC_GET_IFS_INDEX(cu->id); fmt = CODEC_GET_FMT_INDEX(cu->id); xmemchk(); success = codec_table[ifs].cx_encode(fmt, cs->state, (sample*)in_native->data, cu); xmemchk(); return success; }
static int sanity_check_payloads(void) { uint32_t i, j, n_codecs, n_channels; codec_id_t cid; const codec_format_t *cf = NULL; const cc_details_t *ccd = NULL; cc_id_t ccid; u_char pt; n_codecs = codec_get_number_of_codecs(); n_channels = channel_get_coder_count(); for(i = 0; i < n_codecs; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); pt = codec_get_payload(cid); if (pt != CODEC_PAYLOAD_DYNAMIC) { ccid = channel_coder_get_by_payload(pt); for(j = 0; j < n_channels; j++) { ccd = channel_get_coder_details(j); if (ccd == channel_get_null_coder()) { continue; } if (ccd->descriptor == ccid) { debug_msg("clash with %s %s payload (%d)\n", cf->long_name, ccd->name, pt); return FALSE; } } } else { /* codec is not mapped into codec space so ignore */ } } return TRUE; }
int layered_encoder_get_parameters(u_char *state, char *cmd, uint32_t cmd_len) { const codec_format_t *cf; lay_state *l; uint32_t flen; char frag[CODEC_LONG_NAME_LEN+5]; /* XXX/nn/\0 + 1*/ assert(cmd_len > 0); assert(cmd != NULL); l = (lay_state*)state; if (l->n_layers < 2) { debug_msg("Using layered coder with %d layers?\n", l->n_layers); return FALSE; } *cmd = '\0'; flen = 0; cf = codec_get_format(l->codec_id); assert(cf!=NULL); sprintf(frag, "%s/%d", cf->long_name, l->n_layers); flen += strlen(frag); if (flen>cmd_len) { debug_msg("buffer overflow would have occurred.\n"); *cmd = '\0'; return FALSE; } strcat(cmd, frag); cmd[flen] = '\0'; debug_msg("layered parameters: %s\n", cmd); return TRUE; }
int vanilla_decoder_describe (uint8_t pkt_pt, u_char *data, uint32_t data_len, char *out, uint32_t out_len) { codec_id_t pri_id; const codec_format_t *pri_cf; pri_id = codec_get_by_payload(pkt_pt); if (pri_id) { pri_cf = codec_get_format(pri_id); strncpy(out, pri_cf->long_name, out_len); } else { strncpy(out, "Unknown", out_len); } /* string safety - strncpy not always safe */ out[out_len - 1] = '\0'; UNUSED(data); UNUSED(data_len); return TRUE; }
int codec_audio_formats_compatible(codec_id_t id1, codec_id_t id2) { const codec_format_t *cf1, *cf2; int match; assert(codec_id_is_valid(id1)); assert(codec_id_is_valid(id2)); cf1 = codec_get_format(id1); cf2 = codec_get_format(id2); match = !memcmp(&cf1->format, &cf2->format, sizeof(audio_format)); return match; }
static int audio_device_attempt_config(session_t *sp, audio_config *config) { audio_format *inf, *ouf; const codec_format_t *incf; int success; incf = codec_get_format(config->primary); assert(incf); inf = audio_format_dup(&incf->format); ouf = audio_format_dup(&incf->format); if (inf->channels != 2 && config->render_3d) { /* If 3d rendering is enabled we need stereo output * format. */ ouf->channels = 2; } success = audio_open(config->device, inf, ouf); if (success) { mixer_info_t mi; uint16_t unit_len; assert(sp->ms == NULL); assert(sp->tb == NULL); assert(sp->cushion == NULL); audio_non_block(config->device); /* Initialize read and write components */ sp->meter_period = inf->sample_rate / 15; unit_len = inf->bytes_per_block * 8 / (inf->bits_per_sample*inf->channels); tx_create(&sp->tb, sp, (uint16_t)inf->sample_rate, (uint16_t)inf->channels, (uint16_t)unit_len); cushion_create(&sp->cushion, (uint16_t)inf->sample_rate); sp->cur_ts = ts_convert(inf->sample_rate, sp->cur_ts); mi.sample_rate = ouf->sample_rate; mi.channels = ouf->channels; mi.buffer_length = 32640; mix_create(&sp->ms, &mi, sp->cur_ts); if (zero_buf == NULL) { zero_buf = (sample*)xmalloc(unit_len * sizeof(sample)); audio_zero(zero_buf, unit_len, DEV_S16); } } audio_format_free(&inf); audio_format_free(&ouf); return success; }
uint32_t codec_get_samples_per_frame(codec_id_t id) { const codec_format_t *cf; uint32_t spf; assert(codec_id_is_valid(id)); cf = codec_get_format(id); spf = cf->format.bytes_per_block * 8 / (cf->format.channels * cf->format.bits_per_sample); return spf; }
uint32_t codec_peek_frame_size(codec_id_t id, u_char *data, uint16_t blk_len) { uint16_t ifs, fmt; assert(codec_id_is_valid(id)); ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); if (codec_table[ifs].cx_peek_size) { return codec_table[ifs].cx_peek_size(fmt, data, (int)blk_len); } else { const codec_format_t *cf = codec_get_format(id); return cf->mean_coded_frame_size; } }
static int file_and_codec_compatible(const sndfile_fmt_t *sff, codec_id_t cid) { const codec_format_t *cf; cf = codec_get_format(cid); if (cf == NULL) { return FALSE; } if (sff->sample_rate == (uint32_t)cf->format.sample_rate && sff->channels == (uint32_t)cf->format.channels) { return TRUE; } return FALSE; }
static void list_codecs(void) { uint32_t i, cnt; codec_id_t cid; const codec_format_t *cf; cnt = codec_get_number_of_codecs(); for(i = 0; i < cnt; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); printf("%s\n", cf->long_name); } return; }
int vanilla_decoder_peek(uint8_t pkt_pt, u_char *buf, uint32_t len, uint16_t *upp, uint8_t *pt) { codec_id_t cid; assert(buf != NULL); assert(upp != NULL); assert(pt != NULL); cid = codec_get_by_payload(pkt_pt); if (cid) { const codec_format_t *cf; uint32_t unit, done, step; /* Vanilla coding does nothing but group * units. */ cf = codec_get_format(cid); unit = 0; done = cf->mean_per_packet_state_size; while(done < len) { step = codec_peek_frame_size(cid, buf+done, (uint16_t)(len - done)); if (step == 0) { debug_msg("Zero data len for audio unit ?\n"); goto fail; } done += step; unit ++; } assert(done >= len); if (done != len) goto fail; *upp = (uint16_t)unit; *pt = pkt_pt; return TRUE; } fail: *upp = 0; *pt = 255; return FALSE; }
/* For compatibility only */ codec_id_t codec_get_first_mapped_with(uint16_t sample_rate, uint16_t channels) { const codec_format_t *cf; int pt; for(pt = 0; pt < NUM_PAYLOADS; pt++) { if (payload_map[pt]) { cf = codec_get_format(payload_map[pt]); if (cf->format.sample_rate == sample_rate && cf->format.channels == channels) { return payload_map[pt]; } } } debug_msg("No mapped codecs compatible (%d, %d)\n", sample_rate, channels); return 0; }
int codec_map_payload(codec_id_t id, u_char pt) { if (payload_is_valid(pt) && codec_id_is_valid(id)) { if (payload_map[pt] != 0) { codec_unmap_payload(id, pt); } payload_map[pt] = id; codec_map[CODEC_GET_IFS_INDEX(id)][CODEC_GET_FMT_INDEX(id)] = pt; return TRUE; } #ifdef DEBUG { const codec_format_t *cf; cf = codec_get_format(id); debug_msg("Failed to map payload for %s\n", cf->long_name); } #endif /* DEBUG */ return FALSE; }
int redundancy_encoder_get_parameters(u_char *state, char *buf, uint32_t blen) { const codec_format_t *cf; red_enc_state *r; uint32_t i, used, flen; char frag[CODEC_LONG_NAME_LEN+5]; /* XXX/nn/\0 + 1*/ assert(blen > 0); assert(buf != NULL); r = (red_enc_state*)state; if (r->n_layers < 2) { debug_msg("Redundancy encoder has not had parameters set!\n"); return FALSE; } *buf = '\0'; flen = 0; for(i = 0, used = 0; i < r->n_layers; i++) { cf = codec_get_format(r->layer[i].cid); assert(cf != NULL); sprintf(frag, "%s/%d/", cf->long_name, r->layer[i].pkts_off); flen += strlen(frag); if (used+flen > blen) { debug_msg("buffer overflow would have occured.\n"); *buf = '\0'; return FALSE; } strcat(buf + used, frag); used += flen; } buf[used - 1] = '\0'; debug_msg("red parameters: %s\n", buf); return TRUE; }
static void vanilla_decoder_output(channel_unit *cu, struct s_pb *out, timestamp_t playout) { const codec_format_t *cf; codec_id_t id; uint32_t data_len; u_char *p, *end; media_data *m; timestamp_t unit_dur; id = codec_get_by_payload(cu->pt); cf = codec_get_format(id); unit_dur = ts_map32(cf->format.sample_rate, codec_get_samples_per_frame(id)); p = cu->data; end = cu->data + cu->data_len; while(p < end) { media_data_create(&m, 1); m->rep[0]->id = id; if (p == cu->data && cf->mean_per_packet_state_size) { /* First unit out of packet may have state */ m->rep[0]->state_len = cf->mean_per_packet_state_size; m->rep[0]->state = (u_char*)block_alloc(m->rep[0]->state_len); memcpy(m->rep[0]->state, p, cf->mean_per_packet_state_size); p += cf->mean_per_packet_state_size; } /* Now do data section */ data_len = codec_peek_frame_size(id, p, (uint16_t)(end - p)); m->rep[0]->data = (u_char*)block_alloc(data_len); m->rep[0]->data_len = (uint16_t)data_len; memcpy(m->rep[0]->data, p, data_len); if (pb_add(out, (u_char *)m, sizeof(media_data), playout) == FALSE) { debug_msg("Vanilla decode failed\n"); media_data_destroy(&m, sizeof(media_data)); return; } p += data_len; playout = ts_add(playout, unit_dur); } assert(p == end); }
/* Just returns the long name of the codec. * Could display number of layers if really bothered. */ int layered_decoder_describe (uint8_t pkt_pt, u_char *data, uint32_t data_len, char *out, uint32_t out_len) { uint32_t hdr32, slen; uint8_t hdrpt; uint16_t blen, mrk; codec_id_t pri_id; const codec_format_t *pri_cf; UNUSED(pkt_pt); hdr32 = ntohl(*(uint32_t*)data); if(hdr32 & LAY_HDR32_PAT) { hdrpt = (uint8_t)(LAY_HDR32_GET_PT(hdr32)); mrk = (uint16_t)(LAY_HDR32_GET_MRK(hdr32)); blen = (uint16_t)(LAY_HDR32_GET_LEN(hdr32)); pri_id = codec_get_by_payload(hdrpt); if(pri_id) { pri_cf = codec_get_format(pri_id); slen = strlen(pri_cf->long_name); strncpy(out, pri_cf->long_name, out_len); goto done; } } strncpy(out, "Unknown", out_len); done: /* string safety - strncpy not always safe */ out[out_len - 1] = '\0'; UNUSED(data_len); return TRUE; }
static int read_and_encode(coded_unit *out, codec_state *encoder, struct s_sndfile *sf_in) { const codec_format_t *cf; coded_unit dummy; sample *buf; uint16_t req_samples, act_samples; req_samples = codec_get_samples_per_frame(encoder->id); buf = (sample*)block_alloc(sizeof(sample) * req_samples); act_samples = (uint16_t)snd_read_audio(&sf_in, buf, req_samples); if (req_samples != act_samples) { memset(buf + act_samples, 0, sizeof(short) * (req_samples - act_samples)); } cf = codec_get_format(encoder->id); assert(cf != NULL); dummy.id = codec_get_native_coding((uint16_t)cf->format.sample_rate, (uint16_t)cf->format.channels); dummy.state = NULL; dummy.state_len = 0; dummy.data = (u_char*)buf; dummy.data_len = req_samples * sizeof(short); assert(out != NULL); if (codec_encode(encoder, &dummy, out) == FALSE) { abort(); } block_free(dummy.data, dummy.data_len); return (sf_in != NULL); }
int codec_decode(codec_state *cs, coded_unit *in, coded_unit *out) { const codec_format_t *cf; codec_id_t id; uint16_t ifs, fmt, rate, channels; int success; assert(cs != NULL); assert(out != NULL); assert(in != NULL); id = cs->id; assert(in->id == cs->id); assert(codec_is_native_coding(in->id) == FALSE); ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); /* Setup outgoing data block */ cf = codec_get_format(id); assert(out->state == NULL); assert(out->data == NULL); rate = (uint16_t)cf->format.sample_rate; channels = (uint16_t)cf->format.channels; out->id = codec_get_native_coding(rate, channels); out->data_len = cf->format.bytes_per_block; out->data = (u_char*)block_alloc(out->data_len); /* Decode */ xmemchk(); success = codec_table[ifs].cx_decode(fmt, cs->state, in, (sample*)out->data); xmemchk(); return success; }
int codec_can_decode(codec_id_t id) { uint32_t ifs; ifs = CODEC_GET_IFS_INDEX(id); assert(codec_id_is_valid(id)); assert(ifs < NUM_CODEC_INTERFACES); if (codec_table[ifs].cx_can_decode) { /* cx_can_encode only needs to exist if encoder and decoder are asymmetric */ return codec_table[ifs].cx_can_decode(CODEC_GET_FMT_INDEX(id)); } else { const codec_format_t *cf; cf = codec_get_format(id); if (cf->format.sample_rate % 8000) { return FALSE; /* Only m * 8k at moment */ } } return TRUE; }
static void redundancy_decoder_output(channel_unit *chu, struct s_pb *out, timestamp_t playout) { const codec_format_t *cf; codec_id_t cid; u_char *hp, *dp, *de, ppt, bpt; uint32_t hdr32, blen, boff; timestamp_t ts_max_off, ts_blk_off, this_playout; hp = dp = chu->data; de = chu->data + chu->data_len; /* move data pointer past header */ while (ntohl(*((uint32_t*)dp)) & RED_HDR32_PAT) { dp += 4; } if (dp == hp) { debug_msg("Not a redundant block\n"); return; } /* At this point dp points to primary payload type. * This is a most useful quantity... */ ppt = *dp; dp += 1; assert(dp < de); /* Max offset should be in first header. Want max offset * as we nobble timestamps to be: * playout + max_offset - this_offset */ cid = codec_get_by_payload(ppt); if (codec_id_is_valid(cid) == FALSE) { debug_msg("Primary not recognized.\n"); return; } cf = codec_get_format(cid); assert(cf != NULL); hdr32 = ntohl(*(uint32_t*)hp); ts_max_off = ts_map32(cf->format.sample_rate, RED_HDR32_GET_OFF(hdr32)); blen = 0; while (hdr32 & RED_HDR32_PAT) { boff = RED_HDR32_GET_OFF(hdr32); blen = RED_HDR32_GET_LEN(hdr32); bpt = (u_char)RED_HDR32_GET_PT(hdr32); /* Calculate playout point = playout + max_offset - offset */ ts_blk_off = ts_map32(cf->format.sample_rate, boff); this_playout = ts_add(playout, ts_max_off); this_playout = ts_sub(this_playout, ts_blk_off); hp += 4; /* hdr */ red_split_unit(ppt, bpt, dp, blen, this_playout, out); xmemchk(); dp += blen; hdr32 = ntohl(*(uint32_t*)hp); } this_playout = ts_add(playout, ts_max_off); hp += 1; blen = (uint32_t) (de - dp); red_split_unit(ppt, ppt, dp, blen, this_playout, out); xmemchk(); }
static void red_split_unit(u_char ppt, /* Primary payload type */ u_char bpt, /* Block payload type */ u_char *b, /* Block pointer */ uint32_t blen, /* Block len */ timestamp_t playout, /* Block playout time */ struct s_pb *out) /* media buffer */ { const codec_format_t *cf; media_data *md; codec_id_t cid, pid; coded_unit *cu; u_char *p,*pe; timestamp_t step; pid = codec_get_by_payload(ppt); if (!pid) { debug_msg("Payload not recognized\n"); return; } cid = codec_get_by_payload(bpt); if (!cid) { debug_msg("Payload not recognized\n"); return; } if (!codec_audio_formats_compatible(pid, cid)) { debug_msg("Primary (%d) and redundant (%d) not compatible\n", ppt, bpt); return; } cf = codec_get_format(cid); assert(cf != NULL); step = ts_map32(cf->format.sample_rate, codec_get_samples_per_frame(cid)); p = b; pe = b + blen; while(p < pe) { cu = (coded_unit*)block_alloc(sizeof(coded_unit)); cu->id = cid; if (p == b && cf->mean_per_packet_state_size) { cu->state_len = cf->mean_per_packet_state_size; cu->state = block_alloc(cu->state_len); memcpy(cu->state, p, cu->state_len); p += cu->state_len; } else { cu->state = NULL; cu->state_len = 0; } cu->data_len = (uint16_t)codec_peek_frame_size(cid, p, (uint16_t)(pe - p)); cu->data = block_alloc(cu->data_len); memcpy(cu->data, p, cu->data_len); p += cu->data_len; md = red_media_data_create_or_get(out, playout); if (md->nrep == MAX_MEDIA_UNITS) continue; if (place_unit(md, cu) == TRUE) { playout = ts_add(playout, step); } else { /* unit could not be placed - destroy */ if (cu->state_len) { block_free(cu->state, cu->state_len); } block_free(cu->data, cu->data_len); block_free(cu, sizeof(coded_unit)); } } }
int redundancy_decoder_describe (uint8_t pkt_pt, u_char *data, uint32_t data_len, char *out, uint32_t out_len) { const codec_format_t *cf; codec_id_t cid; uint32_t hdr32, slen, blksz, off, nlen; u_char *p, pt; UNUSED(pkt_pt); *out = '\0'; slen = 0; p = data; hdr32 = ntohl(*((uint32_t*)p)); while (hdr32 & RED_HDR32_PAT) { pt = (u_char)RED_HDR32_GET_PT(hdr32); off = RED_HDR32_GET_OFF(hdr32); blksz = RED_HDR32_GET_LEN(hdr32); cid = codec_get_by_payload(pt); if (cid == 0) { p += 4; hdr32 = ntohl(*((uint32_t*)p)); continue; } cf = codec_get_format(cid); assert(cf != NULL); nlen = strlen(cf->long_name); if (slen + nlen >= out_len) { debug_msg("Out of buffer space\n"); return FALSE; } if (slen != 0) { memmove(out + nlen + 1, out, slen); } strncpy(out, cf->long_name, nlen); slen += nlen; out[nlen] = '/'; slen++; out[nlen+1] = '\0'; p += 4; assert((uint32_t)(p - data) < data_len); hdr32 = ntohl(*((uint32_t*)p)); } pt = *p; cid = codec_get_by_payload(pt); if (cid == 0) { return FALSE; } cf = codec_get_format(cid); assert(cf != NULL); nlen = strlen(cf->long_name); if (slen + nlen >= out_len) { debug_msg("Out of buffer space\n"); return FALSE; } memmove(out + nlen + 1, out, slen); strncpy(out, cf->long_name, nlen); out[nlen] = '/'; slen += nlen + 1; /* Axe trailing separator */ out[slen-1] = '\0'; return TRUE; }
static void test_repair(struct s_sndfile *sf_out, codec_id_t cid, repair_id_t repair_type, struct s_sndfile *sf_in) { codec_state *encoder; struct s_codec_state_store *decoder_states; media_data *md_prev, *md_cur; coded_unit *cu; int32_t consec_lost = 0, total_lost, total_done; const codec_format_t *cf; uint16_t i; repair_id_t repair_none; for (i = 0; i < repair_get_count(); i++) { const repair_details_t *rd; rd = repair_get_details(i); if (strcasecmp(rd->name, "none") == 0) { repair_none = rd->id; break; } } codec_encoder_create(cid, &encoder); codec_state_store_create(&decoder_states, DECODER); cf = codec_get_format(cid); /* Read and write one unit to kick off with */ media_data_create(&md_cur, 1); read_and_encode(md_cur->rep[0], encoder, sf_in); decode_and_write(sf_out, decoder_states, md_cur); /* Initialize next reading cycle */ md_prev = md_cur; md_cur = NULL; media_data_create(&md_cur, 1); total_lost = total_done = 0; while(read_and_encode(md_cur->rep[0], encoder, sf_in)) { total_done++; if (do_drop()) { total_lost++; media_data_destroy(&md_cur, sizeof(media_data)); media_data_create(&md_cur, 0); cu = (coded_unit*)block_alloc(sizeof(coded_unit)); assert(cu != NULL); memset(cu, 0, sizeof(coded_unit)); /* Loss happens - invoke repair */ if (repair_type != repair_none) { cu->id = cid; repair(repair_type, consec_lost, decoder_states, md_prev, cu); } else { /* Create a silent unit */ cu->id = codec_get_native_coding((uint16_t)cf->format.sample_rate, (uint16_t)cf->format.channels); cu->state = NULL; cu->state_len = 0; cu->data = (u_char*)block_alloc(cf->format.bytes_per_block); cu->data_len = cf->format.bytes_per_block; memset(cu->data, 0, cu->data_len); } /* Add repaired audio to frame */ md_cur->rep[md_cur->nrep] = cu; md_cur->nrep++; consec_lost++; } else { consec_lost = 0; } decode_and_write(sf_out, decoder_states, md_cur); media_data_destroy(&md_prev, sizeof(media_data)); md_prev = md_cur; md_cur = NULL; media_data_create(&md_cur, 1); } printf("# Dropped %d frames out of %d (%f loss %%)\n", total_lost, total_done, 100.0 * total_lost / (double)total_done); media_data_destroy(&md_cur, sizeof(media_data)); media_data_destroy(&md_prev, sizeof(media_data)); codec_encoder_destroy(&encoder); codec_state_store_destroy(&decoder_states); }
int layered_decoder_peek(uint8_t pkt_pt, u_char *buf, uint32_t len, uint16_t *upp, uint8_t *pt) { codec_id_t cid; u_char *p, *data; uint32_t hdr32; uint8_t hdrpt; uint16_t blen, mrk; assert(buf != NULL); assert(upp != NULL); assert(pt != NULL); UNUSED(pkt_pt); p = data = buf; hdr32 = ntohl(*(uint32_t*)p); if(hdr32 & LAY_HDR32_PAT) { hdrpt = (uint8_t)(LAY_HDR32_GET_PT(hdr32)); mrk = (uint16_t)(LAY_HDR32_GET_MRK(hdr32)); blen = (uint16_t)(LAY_HDR32_GET_LEN(hdr32)); p+=4; data += 4 + blen; hdr32 = ntohl(*(uint32_t*)p); /* assert(((uint32_t)data - (uint32_t)buf) <= blen); */ } else { debug_msg("Invalid layered header\n"); goto fail; } /* I'm haven't decided what exactly to do here yet, so for * the time being if the header seems OK we return TRUE. The * options are: * (i) have a new function codec_peek_layer_frame_size * (ii) work out length of total frame from length in header * (iii) just check that length of packet matches what is in * the header * But what to do about *upp? * The problem is that codec_peek_frame_size, if used with * codec_vdvi, calls vdvi_decode, assuming a complete frame. * Of course we only have one layer at this stage, so the * decode function will fail. I am going to ignore this for * the time being. */ *pt = hdrpt; cid = codec_get_by_payload(*pt); if (cid) { const codec_format_t *cf; uint32_t unit, done, step; /* extra check since the header check seems * to fail quite a lot (why?) */ if(codec_can_layer(cid)==1) goto fail; cf = codec_get_format(cid); unit = 0; done = cf->mean_per_packet_state_size; done += 4; /* step over header */ while(done < len) { step = codec_peek_frame_size(cid, buf+done, (uint16_t)(len)); if (step == 0) { debug_msg("Zero data len for audio unit ?\n"); goto fail; } done += blen; unit ++; } /* assert(done <= len);*/ if (done != len) goto fail; *upp = (uint16_t)unit; return TRUE; } debug_msg("layered_decoder_peek - codec not found\n"); fail: debug_msg("layered_decoder_peek error (len = %d)\n", len); *upp = 0; *pt = 255; return FALSE; }
static int layered_decoder_reorganise(channel_data *in, struct s_pb *out, timestamp_t playout) { const codec_format_t *cf; codec_id_t id; coded_unit *cu; u_char *p[LAY_MAX_LAYERS], *end; uint32_t hdr32, data_len; uint8_t hdrpt, i; uint16_t len[LAY_MAX_LAYERS], mrk[LAY_MAX_LAYERS]; media_data *m; timestamp_t playout_step; media_data_create(&m, 1); assert(m->nrep == 1); if(in->nelem > LAY_MAX_LAYERS) { debug_msg("Too many layers to reorganise\n"); goto done; } /* Since layer_decoder_peek checks all the headers, we can * assume they are OK. We still need to check that they match * up, however, i.e. that all the layers are intact, and that * they are all using the same codec. Layers need to be sorted * into order as well. We use the markers to determine how to * join the layers together into one media_data, and then get * out of here. */ p[0] = in->elem[0]->data; hdr32 = ntohl(*(uint32_t*)p[0]); if(hdr32 & LAY_HDR32_PAT) { hdrpt = (uint8_t)(LAY_HDR32_GET_PT(hdr32)); mrk[0] = (uint8_t)(LAY_HDR32_GET_MRK(hdr32)); len[0] = (uint8_t)(LAY_HDR32_GET_LEN(hdr32)); p[0] += 4; } else { debug_msg("Invalid layered header\n"); goto done; } for(i=1; i<in->nelem; i++) { p[i] = in->elem[i]->data; hdr32 = ntohl(*(uint32_t*)p[i]); if(hdr32 & LAY_HDR32_PAT) { if(hdrpt != (uint8_t)(LAY_HDR32_GET_PT(hdr32))) { debug_msg("layered headers do not match!\n"); goto done; } mrk[i] = (uint16_t)(LAY_HDR32_GET_MRK(hdr32)); len[i] = (uint16_t)(LAY_HDR32_GET_LEN(hdr32)); p[i] += 4; } else { debug_msg("Invalid layered header\n"); goto done; } } end = in->elem[in->nelem-1]->data + in->elem[in->nelem-1]->data_len; /* if layers missing say so */ if(in->nelem!=LAY_MAX_LAYERS) { debug_msg("Not all layers arrived:\n"); for(i=0; i<in->nelem; i++) { debug_msg("marker[%d] = %d\n", i, mrk[i]); } } /* Everything matches, so we'll use the first layer's details */ cu = (coded_unit*)block_alloc(sizeof(coded_unit)); memset(cu, 0, sizeof(coded_unit)); id = codec_get_by_payload(hdrpt); if (codec_id_is_valid(id) == FALSE) { debug_msg("Layered channel coder - codec_id not recognised.\n"); goto fail; } cf = codec_get_format(id); assert(cf != NULL); /* Do first unit separately as that may have state */ if (cf->mean_per_packet_state_size) { cu->state_len = cf->mean_per_packet_state_size; cu->state = (u_char*)block_alloc(cu->state_len); memcpy(cu->state, p[0], cf->mean_per_packet_state_size); for(i=0; i<in->nelem; i++) p[i] += cf->mean_per_packet_state_size; } data_len = codec_peek_frame_size(id, p[0], (uint16_t)(len[0])); m->rep[0]->id = cu->id = id; cu->data = (u_char*)block_alloc(data_len); cu->data_len = (uint16_t)data_len; memset(cu->data, 0, data_len); /* join the layers up here */ for(i=0; i<in->nelem; i++) { memcpy(cu->data + mrk[i], p[i], len[i]); p[i] += len[i]; } codec_combine_layer(id, cu, m->rep[0], in->nelem, mrk); if (cu->state_len) { block_free(cu->state, cu->state_len); cu->state = NULL; cu->state_len = 0; } assert(cu->state_len == 0); if (cu->data_len) { block_free(cu->data, cu->data_len); cu->data = NULL; cu->data_len = 0; } assert(cu->data_len == 0); if (pb_add(out, (u_char *)m, sizeof(media_data), playout) == FALSE) { debug_msg("layered decode failed\n"); goto fail; } /* Now do other units which do not have state*/ playout_step = ts_map32(cf->format.sample_rate, codec_get_samples_per_frame(id)); while(p[in->nelem - 1] < end) { playout = ts_add(playout, playout_step); media_data_create(&m, 1); m->rep[0]->id = id; assert(m->nrep == 1); cu->data = (u_char*)block_alloc(data_len); cu->data_len = (uint16_t)data_len; memset(cu->data, 0, data_len); for(i=0; i<in->nelem; i++) { memcpy(cu->data + mrk[i], p[i], len[i]); p[i] += len[i]; } codec_combine_layer(id, cu, m->rep[0], in->nelem, mrk); block_free(cu->data, cu->data_len); cu->data = 0; cu->data_len = 0; if (pb_add(out, (u_char *)m, sizeof(media_data), playout) == FALSE) { debug_msg("layered decode failed\n"); goto fail; } } assert(p[in->nelem - 1] == end); block_free(cu, sizeof(coded_unit)); channel_data_destroy(&in, sizeof(channel_data)); xmemchk(); return TRUE; fail: if (cu->state) { block_free(cu->state, cu->state_len); cu->state = 0; cu->state_len = 0; } assert(cu->state_len == 0); if (cu->data) { block_free(cu->data, cu->data_len); cu->data = 0; cu->data_len = 0; } assert(cu->data_len == 0); block_free(cu, sizeof(coded_unit)); done: media_data_destroy(&m, sizeof(media_data)); channel_data_destroy(&in, sizeof(channel_data)); xmemchk(); return FALSE; }
int redundancy_encoder_set_parameters(u_char *state, char *cmd) { u_char *encbuf; red_enc_state *n, *cur; const codec_format_t *cf; uint32_t nl, po; codec_id_t cid; char *s; int success = FALSE; assert(state != NULL); assert(cmd != NULL); /* Create a temporary encoder, try to set it's params */ redundancy_encoder_create(&encbuf, &nl); n = (red_enc_state*)encbuf; assert(n != NULL); s = (char *) strtok(cmd, "/"); cid = codec_get_by_name(s); if (!codec_id_is_valid(cid)) { debug_msg("codec not recognized\n"); goto done; } s = (char *) strtok(NULL, "/"); po = atoi(s); if (po > 20) { debug_msg("offset too big\n"); goto done; } n->layer[0].cid = cid; n->layer[0].pkts_off = po; n->n_layers = 1; while (n->n_layers < RED_MAX_LAYERS) { s = (char *) strtok(NULL, "/"); if (s == NULL) break; cid = codec_get_by_name(s); if (!codec_id_is_valid(cid)) { debug_msg("codec not recognized\n"); goto done; } s = (char *) strtok(NULL, "/"); if (s == NULL) { debug_msg("Incomplete layer info\n"); goto done; } po = atoi(s); if (po > 20) { debug_msg("offset too big\n"); goto done; } n->layer[n->n_layers].cid = cid; n->layer[n->n_layers].pkts_off = po; n->n_layers ++; } redundancy_encoder_reset(state); /* Take bits from temporary encoder state we want */ cur = (red_enc_state*)state; memcpy(cur->layer, n->layer, sizeof(red_layer)*RED_MAX_LAYERS); cur->n_layers = n->n_layers; /* work out history = duration of audio frame * maximum offset */ cf = codec_get_format(cur->layer[cur->n_layers - 1].cid); cur->history = ts_map32(cf->format.sample_rate, codec_get_samples_per_frame(cur->layer[cur->n_layers - 1].cid) * cur->layer[cur->n_layers - 1].pkts_off); success = TRUE; done: encbuf = (u_char*)n; redundancy_encoder_destroy(&encbuf, nl); return success; }
void session_init(session_t *sp, int index, int mode) { codec_id_t cid; const codec_format_t *cf = NULL; const converter_details_t *conv = NULL; const cc_details_t *ccd = NULL; uint8_t i; memset(sp, 0, sizeof(session_t)); codec_init(); sanity_check_payloads(); vu_table_init(); cid = codec_get_by_name("DVI-8K-Mono"); assert(cid); cf = codec_get_format(cid); sp->cur_ts = ts_map32(8000,0); sp->encodings[0] = codec_get_payload(cid); /* user chosen encoding for primary */ sp->num_encodings = 1; /* Number of encodings applied */ ccd = channel_get_null_coder(); channel_encoder_create(ccd->descriptor, &sp->channel_coder); conv = converter_get_details(0); sp->converter = conv->id; sp->other_session = NULL; /* Completed in main_engine.c if we're a transoder */ sp->id = index; sp->mode = mode; sp->rtp_session_count = 0; for (i = 0; i < MAX_LAYERS; i++) { sp->rx_rtp_port[i] = sp->tx_rtp_port[i] = sp->rx_rtcp_port[i] = sp->tx_rtcp_port[i] = PORT_UNINIT; sp->rtp_session[i] = NULL; } sp->rx_rtp_port[0] = 5004; /* Default ports per: */ sp->tx_rtp_port[0] = 5004; /* draft-ietf-avt-profile-new-00 */ sp->rx_rtcp_port[0] = 5005; sp->tx_rtcp_port[0] = 5005; sp->ttl = 127; sp->filter_loopback = TRUE; sp->playing_audio = TRUE; sp->lecture = FALSE; sp->auto_lecture = 0; sp->receive_audit_required = FALSE; sp->silence_detection = SILENCE_DETECTION_OFF; sp->sync_on = FALSE; sp->agc_on = FALSE; sp->ui_on = FALSE; sp->meter = TRUE; /* Powermeter operation */ sp->in_file = NULL; sp->out_file = NULL; sp->local_file_player = NULL; sp->mbus_engine_addr = NULL; sp->mbus_engine = NULL; sp->mbus_ui_addr = NULL; sp->mbus_video_addr = xstrdup("(media:video module:engine)"); sp->min_playout = 0; sp->max_playout = 1000; sp->last_depart_ts = 0; sp->loopback_gain = 0; sp->layers = 1; sp->ui_activated = FALSE; sp->encrkey = NULL; sp->logger = NULL; sp->mbus_waiting = FALSE; sp->mbus_waiting_token = NULL; sp->mbus_go = FALSE; sp->mbus_go_token = NULL; sp->magic = 0xcafebabe; /* Magic number for debugging */ source_list_create(&sp->active_sources); sp->title = "Untitled session"; strncpy(sp->asc_address[0], "127.0.0.3", MAXHOSTNAMELEN); /* Yeuch! This value should never be used! */ }
codec_id_t codec_get_matching(const char *short_name, uint16_t freq, uint16_t channels) { /* This has been changed to try really hard to find a matching codec. * The reason is that it's now called as part of the command-line * parsing, and so has to cope with user entered codec names. Also, it * should recognise the names sdr gives the codecs, for compatibility * with rat-v3.0. [csp] */ /* This is not quite as inefficient as it looks, since stage 1 will * almost always find a match. */ const codec_format_t *cf = NULL; codec_id_t cid = 0; uint32_t i, codecs; char *long_name; /* Stage 1: Try the designated short names... */ codecs = codec_get_number_of_codecs(); for(i = 0; i < codecs; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); if (cf->format.sample_rate == freq && cf->format.channels == channels && !strcasecmp(short_name, cf->short_name)) { return cid; } } /* Stage 2: Try to generate a matching name... */ long_name = (char *) xmalloc(strlen(short_name) + 12); sprintf(long_name, "%s-%dK-%s", short_name, freq/1000, channels==1?"MONO":"STEREO"); for(i = 0; i < codecs; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); if (cf->format.sample_rate == freq && cf->format.channels == channels && !strcasecmp(long_name, cf->long_name)) { xfree(long_name); return cid; } } /* Stage 3: Nasty hack... PCM->PCMU for compatibility with sdr * and old rat versions */ if (strncasecmp(short_name, "pcm", 3) == 0) { sprintf(long_name, "PCMU-%dK-%s", freq/1000, channels==1?"MONO":"STEREO"); for(i = 0; i < codecs; i++) { cid = codec_get_codec_number(i); cf = codec_get_format(cid); if (cf->format.sample_rate == freq && cf->format.channels == channels && !strcasecmp(long_name, cf->long_name)) { xfree(long_name); return cid; } } } xfree(long_name); debug_msg("Unable to find codec \"%s\" at rate %d channels %d\n", short_name, freq, channels); return 0; }
int redundancy_decoder_peek(uint8_t pkt_pt, u_char *buf, uint32_t len, uint16_t *upp, uint8_t *pt) { const codec_format_t *cf; codec_id_t cid; u_char *p, *data; uint32_t hdr32, dlen, blen; uint16_t units; assert(buf != NULL); assert(upp != NULL); assert(pt != NULL); /* Just check primary, so skip over other headers and * advance data pointer past them. */ p = data = buf; hdr32 = ntohl(*(uint32_t*)p); while ((hdr32 & RED_HDR32_PAT)) { blen = RED_HDR32_GET_LEN(hdr32); p += 4; /* goto next hdr */ data += 4 + blen; hdr32 = ntohl(*(uint32_t*)p); assert(((unsigned long)data - (unsigned long)buf) <= len); } *pt = *p; data += 1; /* step over payload field of primary */ cid = codec_get_by_payload(*pt); if (!cid) { debug_msg("Codec not found\n"); return FALSE; } /* Primary data length */ dlen = len - (uint32_t)(data - buf); cf = codec_get_format(cid); assert(cf); data += cf->mean_per_packet_state_size; dlen -= cf->mean_per_packet_state_size; assert(((unsigned long)data - (unsigned long)buf) <= len); units = 0; while (dlen != 0) { blen = codec_peek_frame_size(cid, p, (uint16_t)dlen); assert(blen != 0); data += blen; dlen -= blen; units ++; assert(((unsigned long)data - (unsigned long)buf) <= len); } *upp = units; assert(*upp < 50); UNUSED(pkt_pt); return TRUE; }