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; }
int codec_decoder_repair(codec_id_t id, codec_state *cs, uint16_t consec_missing, coded_unit *prev, coded_unit *miss, coded_unit *next) { uint16_t ifs, fmt; assert(codec_id_is_valid(id)); assert(id == cs->id); ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); if (miss->id != id) { debug_msg("Wrong previous unit supplied for repair. Probably a transition in stream.\n"); return FALSE; } miss->id = prev->id; assert(codec_table[ifs].cx_repair != NULL); return codec_table[ifs].cx_repair(fmt, cs->state, consec_missing, prev, miss, next); }
/* Decoder related ***********************************************************/ int codec_decoder_create(codec_id_t id, codec_state **cs) { if (codec_id_is_valid(id)) { uint16_t ifs, fmt; *cs = (codec_state*)block_alloc(sizeof(codec_state)); if (!cs) { *cs = NULL; return 0; } (*cs)->state = NULL; (*cs)->id = id; ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); if (codec_table[ifs].cx_decoder_create) { /* Must also have a destructor */ assert(codec_table[ifs].cx_decoder_destroy != NULL); codec_table[ifs].cx_decoder_create(fmt, &(*cs)->state); } return TRUE; } else { debug_msg("Attempting to initiate invalid codec\n"); abort(); } return 0; }
int layered_encoder_set_parameters(u_char *state, char *cmd) { u_char *nbuf; lay_state *n, *cur; codec_id_t cid; char *s; uint8_t layers; uint32_t nl; int success = FALSE; assert(state != NULL); assert(cmd != NULL); /* Create a temporary encoder, try to set its params */ layered_encoder_create(&nbuf, &nl); n = (lay_state*)nbuf; assert(n != NULL); if(strcmp(cmd, "None")==0) { /*might happen from load_settings */ debug_msg("layered codec not recognised\n"); goto done; } s = (char *) strtok(cmd, "/"); if(s==NULL) { debug_msg("layered_codec_not_recognised\n"); goto done; } cid = codec_get_by_name(s); if (!codec_id_is_valid(cid)) { debug_msg("layered codec not recognized\n"); goto done; } n->codec_id = cid; s = (char *) strtok(NULL, "/"); layers = atoi(s); if(layers>codec_can_layer(cid) || layers>LAY_MAX_LAYERS) { debug_msg("Too many layers (%d)\n", layers); goto done; } n->n_layers = layers; layered_encoder_reset(state); /* Take bits from temporary encoder state we want */ cur = (lay_state*)state; cur->codec_id = n->codec_id; cur->n_layers = n->n_layers; success = TRUE; done: nbuf = (u_char*)n; layered_encoder_destroy(&nbuf, nl); return success; }
const codec_format_t* codec_get_format(codec_id_t id) { uint16_t ifs, fmt; assert(codec_id_is_valid(id)); ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); return codec_table[ifs].cx_get_format(fmt); }
int codec_decoder_can_repair (codec_id_t id) { uint16_t ifs; assert(codec_id_is_valid(id)); ifs = CODEC_GET_IFS_INDEX(id); if (codec_table[ifs].cx_repair) { return TRUE; } else { return FALSE; } }
int codec_unmap_payload(codec_id_t id, u_char pt) { if (payload_is_valid(pt) && codec_id_is_valid(id) && payload_map[pt] == id) { payload_map[pt] = 0; codec_map[CODEC_GET_IFS_INDEX(id)][CODEC_GET_FMT_INDEX(id)] = CODEC_PAYLOAD_DYNAMIC; return TRUE; } debug_msg("Failed to unmap payload\n"); return FALSE; }
u_char codec_get_payload(codec_id_t id) { u_char pt; assert(codec_id_is_valid(id)); pt = codec_map[CODEC_GET_IFS_INDEX(id)][CODEC_GET_FMT_INDEX(id)]; if (payload_is_valid(pt)) { assert(codec_get_by_payload(pt) == id); return pt; } return CODEC_PAYLOAD_DYNAMIC; }
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; }
/* Layered codecs ***********************************************************/ uint8_t codec_can_layer(codec_id_t id) { uint16_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_layer) { return codec_table[ifs].cx_can_layer(); } return 1; }
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; } }
codec_id_t codec_get_codec_number(uint32_t n) { codec_id_t id; uint32_t ifs; assert(n < total_fmts_supported); for(ifs = 0; n >= num_fmts_supported[ifs]; ifs++) { n = n - num_fmts_supported[ifs]; } id = CODEC_MAKE_ID(ifs, n); assert(codec_id_is_valid(id)); return id; }
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; }
void codec_decoder_destroy(codec_state **cs) { codec_id_t id; assert(*cs != NULL); id = (*cs)->id; if (codec_id_is_valid(id)) { uint16_t ifs, fmt; ifs = CODEC_GET_IFS_INDEX(id); fmt = CODEC_GET_FMT_INDEX(id); if (codec_table[ifs].cx_decoder_destroy) { /* Must also have a destructor */ codec_table[ifs].cx_decoder_destroy(fmt, &(*cs)->state); } block_free(*cs, sizeof(codec_state)); *cs = NULL; } else { debug_msg("Destroying corrupted codec\n"); abort(); } }
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; }
void settings_load_early(session_t *sp) { /* FIXME: This needs to be updated for the transcoder */ char *name, *param, *primary_codec, *port, *silence; int freq, chan, mute; uint32_t i, n, success, device_exists; const cc_details_t *ccd; const audio_device_details_t *add = NULL; const audio_port_details_t *apd = NULL; const converter_details_t *cod = NULL; const repair_details_t *r = NULL; codec_id_t cid; load_init(); /* Initial settings come from the common prefs file... */ init_part_two(); /* Switch to pulling settings from the RAT specific prefs file... */ if (sp->mode == AUDIO_TOOL) { name = setting_load_str("audioDevice", "No Audio Device"); } else { name = (char *) xmalloc(20); sprintf(name, "Transcoder Port %d", sp->id+1); } /* User may not have a (valid) audio device entry in the */ /* settings file, or have "No Audio Device" there. In */ /* either case try to use first available device, if */ /* it's in use we'll fallback to dummy device anyway. */ device_exists = FALSE; n = (int)audio_get_device_count(); for(i = 0; i < n; i++) { add = audio_get_device_details(i); if (strcmp(add->name, name) == 0) { device_exists = TRUE; break; } } if (strcmp(name, "No Audio Device") == 0 || device_exists == FALSE) { add = audio_get_device_details(0); } audio_device_register_change_device(sp, add->descriptor); freq = setting_load_int("audioFrequency", 8000); chan = setting_load_int("audioChannelsIn", 1); primary_codec = setting_load_str("audioPrimary", "GSM"); cid = codec_get_matching(primary_codec, (uint16_t)freq, (uint16_t)chan); if (codec_id_is_valid(cid) == FALSE) { /* Codec name is garbage...should only happen on upgrades */ cid = codec_get_matching("GSM", (uint16_t)freq, (uint16_t)chan); } audio_device_register_change_primary(sp, cid); audio_device_reconfigure(sp); port = setting_load_str("audioOutputPort", "Headphone"); n = audio_get_oport_count(sp->audio_device); for(i = 0; i < n; i++) { apd = audio_get_oport_details(sp->audio_device, i); if (!strcasecmp(port, apd->name)) { break; } } audio_set_oport(sp->audio_device, apd->port); port = setting_load_str("audioInputPort", "Microphone"); n = audio_get_iport_count(sp->audio_device); for(i = 0; i < n; i++) { apd = audio_get_iport_details(sp->audio_device, i); if (!strcasecmp(port, apd->name)) { break; } } audio_set_iport(sp->audio_device, apd->port); audio_set_ogain(sp->audio_device, setting_load_int("audioOutputGain", 75)); audio_set_igain(sp->audio_device, setting_load_int("audioInputGain", 75)); tx_igain_update(sp->tb); name = setting_load_str("audioChannelCoding", "None"); param = setting_load_str("audioChannelParameters", "None"); do { n = channel_get_coder_count(); for (i = 0; i < n; i++ ) { ccd = channel_get_coder_details(i); if (strcmp(ccd->name, name) == 0) { if (sp->channel_coder) { channel_encoder_destroy(&sp->channel_coder); } channel_encoder_create(ccd->descriptor, &sp->channel_coder); break; } } success = channel_encoder_set_parameters(sp->channel_coder, param); if (success == 0) { /* Could not set parameters for channel coder, fall back to "None" */ name = "None"; param = ""; } } while (success == 0); channel_encoder_set_units_per_packet(sp->channel_coder, (uint16_t) setting_load_int("audioUnits", 1)); /* Set default repair to be first available */ r = repair_get_details(0); sp->repair = r->id; name = setting_load_str("audioRepair", "Pattern-Match"); n = (int)repair_get_count(); for(i = 0; i < n; i++) { r = repair_get_details((uint16_t)i); if (strcasecmp(r->name, name) == 0) { sp->repair = r->id; break; } } /* Set default converter to be first available */ cod = converter_get_details(0); sp->converter = cod->id; name = setting_load_str("audioAutoConvert", "High Quality"); n = (int)converter_get_count(); /* If converter setting name matches then override existing choice */ for(i = 0; i < n; i++) { cod = converter_get_details(i); if (strcasecmp(cod->name, name) == 0) { sp->converter = cod->id; break; } } silence = setting_load_str("audioSilence", "Automatic"); sp->silence_detection = sd_name_to_type(silence); sp->manual_sd_thresh = setting_load_int("audioSilenceManualThresh", 100); if (sp->manual_sd) { manual_sd_set_thresh(sp->manual_sd, sp->manual_sd_thresh); } sp->limit_playout = setting_load_int("audioLimitPlayout", 0); sp->min_playout = setting_load_int("audioMinPlayout", 0); sp->max_playout = setting_load_int("audioMaxPlayout", 2000); sp->lecture = setting_load_int("audioLecture", 0); sp->agc_on = setting_load_int("audioAGC", 0); sp->loopback_gain = setting_load_int("audioLoopback", 0); audio_loopback(sp->audio_device, sp->loopback_gain); sp->echo_suppress = setting_load_int("audioEchoSuppress", 0); sp->meter = setting_load_int("audioPowermeters", 1); sp->rtp_promiscuous_mode = setting_load_int("rtpPromiscuousMode", 0); sp->rtp_wait_for_rtcp = setting_load_int("rtpWaitForRTCP", 1); /* Ignore saved render_3d setting. Break initial device config stuff. V.fiddly to fix. */ /* sp->render_3d = setting_load_int("audio3dRendering", 0); */ mute = setting_load_int("audioInputMute", sp->mode==TRANSCODER?0:1); if (mute && tx_is_sending(sp->tb)) { tx_stop(sp->tb); } else if (mute == 0 && tx_is_sending(sp->tb) == 0) { tx_start(sp->tb); } setting_load_int("audioOutputMute", 1); xmemchk(); load_done(); }
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; }
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(); }
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; }