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; }
int main() { static rtp_packet *pp; static pktbuf_t *pb; int32_t i, j, n,ts; if (pktbuf_create(&pb, PKTBUF_SIZE) == 0) { printf("Failed to create buffer\n"); exit(-1); } xmemchk(); for(i = 0; i < 100000; i++) { n = lrand48() % 16; for(j = 0; j <= n; j++) { pp = (rtp_packet*)xmalloc(sizeof(rtp_packet)); pp->ts = ts ++; add_thing(pb, pp); } n = lrand48() % 16; for(j = 0; j < n; j++) { remove_thing(pb); } } pktbuf_destroy(&pb); xmemdmp(); printf("Okay\n"); return 0; }
static void sinc_downsample_mono(struct s_filter_state *fs, sample *src, int src_len, sample *dst, int dst_len) { int32_t *hc, *he, t, work_len; sample *work_buf, *ss, *sc, *de, *d; work_len = src_len + fs->taps; work_buf = (sample*)block_alloc(work_len * sizeof(sample)); /* Get samples into work_buf */ memcpy(work_buf, fs->hold_buf, fs->hold_bytes); memcpy(work_buf + fs->hold_bytes / sizeof(sample), src, src_len * sizeof(sample)); /* Save last samples in src into hold_buf for next time */ if (src_len >= (int)(fs->hold_bytes / sizeof(sample))) { memcpy(fs->hold_buf, src + src_len - fs->hold_bytes / sizeof(sample), fs->hold_bytes); } else { /* incoming chunk was shorter than hold buffer */ memmove(fs->hold_buf, fs->hold_buf + src_len, fs->hold_bytes - src_len * sizeof(sample)); memcpy(fs->hold_buf + fs->hold_bytes / sizeof(sample) - src_len, src, src_len * sizeof(sample)); } d = dst; de = dst + dst_len; sc = ss = work_buf; he = fs->filter + fs->taps; while (d != de) { t = 0; hc = fs->filter; while(hc < he) { t += (*sc) * (*hc); sc++; hc++; } t = t / SINC_SCALE; clip16(t); *d = (sample) t; d++; ss += fs->scale; sc = ss; } assert(d == dst + dst_len); block_free(work_buf, work_len * sizeof(sample)); xmemchk(); }
static void add_thing(pktbuf_t *pb, rtp_packet *pp) { pktbuf_enqueue(pb, pp); if (buf_est < PKTBUF_SIZE) { buf_est++; } assert(buf_est == pktbuf_get_count(pb)); xmemchk(); }
static uint32_t make_pdu(struct s_pb_iterator *pbi, uint32_t upp, codec_id_t cid, channel_data *out) { struct s_pb_iterator *p; uint32_t i, j, md_len, used; u_char *md_get; media_data *md; timestamp_t playout; int success; pb_iterator_dup(&p, pbi); used = 0; for (i = 0; i < upp; i++) { success = pb_iterator_get_at(p, &md_get, &md_len, &playout); md = (media_data*)md_get; assert(success); /* We could rewind this far so must be able to get something! */ /* Find first compatible coding */ for(j = 0; j < md->nrep && md->rep[j]->id != cid; j++); if (j == md->nrep) { /* could not find coding */ debug_msg("coding not found\n"); break; } if (i == 0 && md->rep[j]->state != NULL) { /* This is first unit in block so we want state */ assert(out->elem[used]->data == NULL); out->elem[used]->data = md->rep[j]->state; out->elem[used]->data_len = md->rep[j]->state_len; md->rep[j]->state = NULL; md->rep[j]->state_len = 0; used++; } assert(used < out->nelem); assert(out->elem[used]->data == NULL); out->elem[used]->data = md->rep[j]->data; out->elem[used]->data_len = md->rep[j]->data_len; md->rep[j]->data = NULL; md->rep[j]->data_len = 0; md->rep[j]->id = 0; /* nobble this unit since we have taken it's data */ used++; assert(used <= out->nelem); pb_iterator_advance(p); } pb_iterator_destroy(pb_iterator_get_playout_buffer(pbi), &p); xmemchk(); return used; }
static void remove_thing(pktbuf_t *pb) { rtp_packet *pp; if (pktbuf_dequeue(pb, &pp)) { xfree(pp); buf_est --; } assert(buf_est == pktbuf_get_count(pb)); xmemchk(); }
void sinc_shutdown (void) { int i; xmemchk(); for (i = SINC_MIN_CHANGE; i < SINC_MAX_CHANGE; i++) { xfree(upfilter[i]); xfree(downfilter[i]); } }
/** * xfree: * @p: pointer to block to freed. * * Free block of memory. Semantically equivalent to free(), but * checks for bounds overruns in @p and tidies up state associated * additional functionality. * * Must be used to free memory allocated with xmalloc(), xrealloc(), * and xstrdup(). **/ void xfree(void *p) { alloc_blk *m; chk_header *ch; uint32_t size, delta, magic, idx; if (p == NULL) { printf("ERROR: Attempt to free NULL pointer!\n"); abort(); } ch = ((chk_header*)p) - 1; printf("free at %p\n", ch); /* Validate entry */ if (chk_header_okay(ch) == FALSE) { printf("ERROR: Freeing corrupted block\n"); abort(); } /* Locate in table */ m = mem_item_find(ch->key); if (m == NULL) { printf("ERROR: Freeing unallocated or already free'd block\n"); abort(); } /* Trash memory of allocated block, maybe noticed by apps when * deref'ing free'd */ size = ch->size + sizeof(chk_header) + MAGIC_MEMORY_SIZE; magic = MAGIC_MEMORY; p = (uint8_t*)ch; while (size > 0) { delta = min(size, 4); memcpy(p, &magic, delta); (uint8_t*)p += delta; size -= delta; } /* Free memory */ free(ch); free(m->filen); /* Remove from table */ idx = m - mem_item; if (naddr - idx > 0) { memmove(&mem_item[idx], &mem_item[idx + 1], (naddr - idx - 1) * sizeof(alloc_blk)); } naddr--; xmemchk(); }
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; }
void asarray_destroy(asarray **ppa) { asarray *pa; const char *key; pa = *ppa; assert(pa != NULL); while ((key = asarray_get_key_no(pa, 0)) != NULL) { asarray_remove(pa, key); } xfree(pa); *ppa = NULL; xmemchk(); }
static int audio_device_write(session_t *sp, sample *buf, int dur) { const audio_format *ofmt = audio_get_ofmt(sp->audio_device); int len; assert(dur >= 0); if (sp->out_file) { snd_write_audio(&sp->out_file, buf, (uint16_t)(dur * ofmt->channels)); } len = audio_write(sp->audio_device, buf, dur * ofmt->channels); xmemchk(); return len; }
static void oss_pair_devices(void) { /* This function scans through the devices[] array, merging pairs */ /* of half-duplex audio devices into a single full duplex device */ /* entry (with one device providing half-duplex recording, and the */ /* other providing half-duplex playback). */ int i, j; if (num_devices < 2) { return; } for (i = 0; i < num_devices - 1; i++) { if ((devices[i].duplex == OSS_DUPLEX_HALF) && (devices[i+1].duplex == OSS_DUPLEX_HALF)) { if (oss_test_device_pair(i, i+1)) { debug_msg("Combining %s and %s\n", devices[i].audio_rdev, devices[i+1].audio_wdev); memcpy(devices[i].audio_wdev, devices[i+1].audio_wdev, 16); if (strlen(devices[i+1].mixer_wdev) != 0) { debug_msg("Second mixer is valid\n"); memcpy(devices[i].mixer_wdev, devices[i+1].mixer_wdev, 16); } else { debug_msg("Second mixer is invalid - assuming first is okay\n"); } devices[i].audio_rfd = -1; devices[i].audio_wfd = -1; devices[i].mixer_rfd = -1; devices[i].mixer_wfd = -1; devices[i].duplex = OSS_DUPLEX_PAIR; devices[i].rec_mask = devices[i+1].rec_mask; xfree(devices[i+1].name); /* Move the rest of the device table up... */ for (j = i+1; j < (num_devices - 1); j++) { devices[j] = devices[j+1]; } xmemchk(); num_devices--; i--; } else { debug_msg("Cannot pair %s and %s\n", devices[i].audio_rdev, devices[i+1].audio_wdev); } } } }
static void setting_save_int(const char *name, const long val) { #ifndef WIN32 char sval[12]; sprintf(sval, "%ld", val); asarray_add(aa, name, sval); xmemchk(); #else LONG status; char buffer[SETTINGS_BUF_SIZE]; status = RegSetValueEx(cfgKey, name, 0, REG_DWORD, &(char)val, sizeof(val)); if (status != ERROR_SUCCESS) { FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, status, 0, buffer, SETTINGS_BUF_SIZE, NULL); debug_msg("Unable to save setting %s: %s\n", name, buffer); abort(); } #endif }
static int codec_state_store_expand(codec_state_store_t *css) { int i; codec_state **buffer; /* This should very very rarely get called */ buffer = (codec_state**)xmalloc((css->allocated + CODEC_STORE_UNIT_SIZE) * sizeof(codec_state*)); memset(buffer + CODEC_STORE_UNIT_SIZE*sizeof(codec_state*), 0, CODEC_STORE_UNIT_SIZE*sizeof(codec_state*)); for(i = 0; i < css->allocated; i++) { buffer[i] = css->buffer[i]; } xmemchk(); xfree(css->buffer); css->buffer = buffer; css->allocated += CODEC_STORE_UNIT_SIZE; return TRUE; }
/* This function needs to be modified to return some indication of how well * or not we are doing. */ int audio_rw_process(session_t *spi, session_t *spo, struct s_mixer *ms) { uint32_t cushion_size, read_dur; struct s_cushion_struct *c; int trailing_silence, new_cushion, cushion_step, diff; const audio_format* ofmt; sample *bufp; session_validate(spi); session_validate(spo); c = spi->cushion; if ((read_dur = tx_read_audio(spi->tb)) <= 0) { return 0; } else { if (!spi->audio_device) { /* no device means no cushion */ return read_dur; } } xmemchk(); /* read_dur now reflects the amount of real time it took us to get * through the last cycle of processing. */ if (spo->lecture == TRUE && spo->auto_lecture == 0) { cushion_update(c, read_dur, CUSHION_MODE_LECTURE); } else { cushion_update(c, read_dur, CUSHION_MODE_CONFERENCE); } /* Following code will try to achieve new cushion size without * messing up the audio... * First case is when we are in trouble and the output has gone dry. * In this case we write out a complete new cushion with the desired * size. We do not care how much of it is going to be real audio and * how much silence so long as the silence is at the head of the new * cushion. If the silence was at the end we would be creating * another silence gap... */ cushion_size = cushion_get_size(c); ofmt = audio_get_ofmt(spi->audio_device); if (cushion_size < read_dur) { debug_msg("catch up! read_dur(%d) > cushion_size(%d)\n", read_dur, cushion_size); /* Use a step for the cushion to keep things nicely rounded */ /* in the mixing. Round it up. */ new_cushion = cushion_use_estimate(c); assert(new_cushion >= 0 && new_cushion < 100000); /* The mix routine also needs to know for how long the */ /* output went dry so that it can adjust the time. */ mix_new_cushion(ms, cushion_size, new_cushion, (read_dur - cushion_size), &bufp); audio_device_write(spo, bufp, new_cushion); /* We've blocked for this long for whatever reason */ cushion_size = new_cushion; } else { trailing_silence = mix_get_audio(ms, read_dur * ofmt->channels, &bufp); cushion_step = cushion_get_step(c); diff = 0; if (trailing_silence > cushion_step) { /* Check whether we need to adjust the cushion */ diff = cushion_diff_estimate_size(c); if (abs(diff) < cushion_step) { diff = 0; } } /* If diff is less than zero then we must decrease the */ /* cushion so loose some of the trailing silence. */ if (diff < 0 && mix_active(ms) == FALSE && source_list_source_count(spi->active_sources) == 0) { /* Only decrease cushion if not playing anything out */ uint32_t old_cushion; old_cushion = cushion_get_size(c); if (read_dur > (unsigned)cushion_step) { cushion_step_down(c); if (cushion_get_size(c) != old_cushion) { debug_msg("Decreasing cushion\n"); read_dur -= cushion_step; } } } assert(read_dur < 0x7fffffff); audio_device_write(spo, bufp, read_dur); /* * If diff is greater than zero then we must increase the * cushion so increase the amount of trailing silence. */ if (diff > 0) { assert(cushion_step > 0); audio_device_write(spo, zero_buf, cushion_step); cushion_step_up(c); debug_msg("Increasing cushion.\n"); } } return (read_dur); }
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 layered_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; lay_state *le = (lay_state*)state; assert(upp != 0 && upp <= MAX_UNITS_PER_PACKET); pb_iterator_create(in, &pi); pb_iterator_advance(pi); /* Move to first element */ while(pb_iterator_detach_at(pi, &m_get, &m_len, &playout)) { /* Remove element from playout buffer - it belongs to * the layered encoder now. */ m = (media_data*)m_get; assert(m != NULL); if (le->nelem == 0) { /* If it's the first unit make a note of it's * playout */ le->playout = playout; if (m->nrep == 0) { /* We have no data ready to go and no data * came off on incoming queue. */ media_data_destroy(&m, sizeof(media_data)); continue; } } else { /* Check for early send required: * (a) if this unit has no media respresentations * e.g. end of talkspurt. * (b) codec type of incoming unit is different * from what is on queue. */ if (m->nrep == 0) { layered_encoder_output(le, out); media_data_destroy(&m, sizeof(media_data)); continue; } else if (m->rep[0]->id != le->codec_id) { layered_encoder_output(le, out); } } assert(m_len == sizeof(media_data)); le->codec_id = m->rep[0]->id; le->elem[le->nelem] = m; le->nelem++; if (le->nelem >= (uint32_t)upp) { layered_encoder_output(le, out); } } pb_iterator_destroy(in, &pi); xmemchk(); return TRUE; }
static void sinc_downsample_stereo(struct s_filter_state *fs, sample *src, int src_len, sample *dst, int dst_len) { int32_t *hc, *he, t0, t1, work_len; sample *work_buf, *ss, *sc, *d, *de; /* work_len = src_len + 2 * (fs->taps - fs->scale); */ work_len = src_len + fs->hold_bytes / sizeof(sample); work_buf = (sample*)block_alloc(work_len * sizeof(sample)); /* Get samples into work_buf */ memcpy(work_buf, fs->hold_buf, fs->hold_bytes); xmemchk(); memcpy(work_buf + fs->hold_bytes / sizeof(sample), src, src_len * sizeof(sample)); xmemchk(); /* Save last samples in src into hold_buf for next time */ if (src_len >= (int)(fs->hold_bytes / sizeof(sample))) { memcpy(fs->hold_buf, src + src_len - fs->hold_bytes / sizeof(sample), fs->hold_bytes); } else { /* incoming chunk was shorter than hold buffer */ memmove(fs->hold_buf, fs->hold_buf + src_len, fs->hold_bytes - src_len * sizeof(sample)); memcpy(fs->hold_buf + fs->hold_bytes / sizeof(sample) - src_len, src, src_len * sizeof(sample)); } d = dst; de = dst + dst_len; sc = ss = work_buf; he = fs->filter + fs->taps; while (d < de) { t0 = t1 = 0; hc = fs->filter; sc = ss; while(hc < he) { t0 += (*sc) * (*hc); sc++; t1 += (*sc) * (*hc); sc++; hc++; } t0 = t0 / SINC_SCALE; if (t0 > 32767) { *d = 32767; } else if (t0 < -32768) { *d = -32768; } else { *d = (sample) t0; } d++; t1 = t1 / SINC_SCALE; if (t1 > 32767) { *d = 32767; } else if (t1 < -32768) { *d = -32768; } else { *d = (sample) t1; } d++; ss += fs->scale * 2; } assert(d == dst + dst_len); block_free(work_buf, work_len * sizeof(sample)); xmemchk(); }
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 channel_data * redundancy_encoder_output(red_enc_state *re, uint32_t upp) { struct s_pb_iterator *pbm; channel_data *cd_coded[RED_MAX_LAYERS], *cd_out; uint32_t offset ; int i, j, layers, success = 0, used = 0; pbm = re->media_pos; pb_iterator_ffwd(pbm); /*** Stage 1: Packing coded audio units ******************************/ /* Rewind iterator to start of first pdu */ for(i = 1; (uint32_t)i < upp; i++) { success = pb_iterator_retreat(pbm); assert(success); } offset = 0; layers = 0; for (i = 0; (uint32_t)i < re->n_layers; i++) { if (re->units_ready <= re->layer[i].pkts_off * upp) { break; } /* Move back to start of this layer */ while (offset < re->layer[i].pkts_off * upp) { success = pb_iterator_retreat(pbm); if (success == FALSE) break; offset++; } xmemchk(); /* need upp data elements + 1 for state */ channel_data_create(&cd_coded[i], upp + 1); success = make_pdu(pbm, upp, re->layer[i].cid, cd_coded[i]); /* make_pdu may fail because coding not available */ if (success == FALSE) { channel_data_destroy(&cd_coded[i], sizeof(channel_data)); break; } layers++; } #ifdef DEBUG_REDUNDANCY debug_msg("end of data collection\n"); #endif /* DEBUG_REDUNDANCY */ assert(layers != 0); /* Create channel_data unit that will get output */ channel_data_create(&cd_out, layers * (upp + 1) + re->n_layers); /*** Stage 2: Packing redundancy headers *****************************/ used = 0; if ((uint32_t)layers != re->n_layers) { /* Add max offset if we didn't make all units */ add_hdr(cd_out->elem[used], RED_EXTRA, re->layer[re->n_layers - 1].cid, re->layer[re->n_layers - 1].pkts_off * upp, 0); used++; } i = layers - 1; while (i > 0) { add_hdr(cd_out->elem[used], RED_EXTRA, re->layer[re->n_layers - 1].cid, re->layer[re->n_layers - 1].pkts_off * upp, channel_data_bytes(cd_coded[i])); used++; i--; } add_hdr(cd_out->elem[used], RED_PRIMARY, re->layer[0].cid, re->layer[0].pkts_off * upp, 0); used++; /*** Stage 3: Transfering coded units into output unit ***************/ for(i = layers - 1; i >= 0; i--) { for (j = 0; j < cd_coded[i]->nelem && cd_coded[i]->elem[j]->data != NULL; j++) { cd_out->elem[used]->data = cd_coded[i]->elem[j]->data; cd_out->elem[used]->data_len = cd_coded[i]->elem[j]->data_len; cd_coded[i]->elem[j]->data = NULL; cd_coded[i]->elem[j]->data_len = 0; used++; assert(used <= cd_out->nelem); } assert(used <= cd_out->nelem); channel_data_destroy(&cd_coded[i], sizeof(channel_data)); } pb_iterator_audit(pbm, re->history); /* Clear old rubbish */ return cd_out; }
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 void sinc_upsample_stereo (struct s_filter_state *fs, sample *src, int src_len, sample *dst, int dst_len) { sample *work_buf, *out; int work_len; int32_t tmp[2], si_start, si_end, si, hold_bytes; int32_t *h, hi_start, hi_end, hi; hold_bytes = fs->taps / fs->scale * sizeof(sample) * 2; work_len = src_len + hold_bytes / sizeof(sample); work_buf = (sample*)block_alloc(sizeof(sample)*work_len); /* Get samples into work_buf */ memcpy(work_buf, fs->hold_buf, hold_bytes); memcpy(work_buf + hold_bytes / sizeof(sample), src, src_len * sizeof(sample)); /* Save last samples in src into hold_buf for next time */ if (src_len >= (int)(hold_bytes / sizeof(sample))) { memcpy(fs->hold_buf, src + src_len - hold_bytes / sizeof(sample), hold_bytes); } else { /* incoming chunk was shorter than hold buffer */ memmove(fs->hold_buf, fs->hold_buf + src_len, hold_bytes - src_len * sizeof(sample)); memmove(fs->hold_buf + hold_bytes / sizeof(sample) - src_len, src, src_len * sizeof(sample)); } h = fs->filter; hi_end = fs->taps; si_start = 0; si_end = work_len - (fs->taps / fs->scale) * 2; out = dst; switch (fs->scale) { case 6: while (si_start < si_end) { si = si_start; tmp[0] = tmp[1] = 0; hi = 5; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 4; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 3; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 2; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 1; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 0; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si_start += 2; } break; case 5: while (si_start < si_end) { si = si_start; tmp[0] = tmp[1] = 0; hi = 4; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 3; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 2; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 1; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 0; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si_start += 2; } break; case 4: while (si_start < si_end) { si = si_start; tmp[0] = tmp[1] = 0; hi = 3; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 2; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 1; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 0; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si_start += 2; } break; case 3: while (si_start < si_end) { si = si_start; tmp[0] = tmp[1] = 0; hi = 2; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 1; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 0; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si_start += 2; } break; case 2: while (si_start < si_end) { si = si_start; tmp[0] = tmp[1] = 0; hi = 1; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si = si_start; tmp[0] = tmp[1] = 0; hi = 0; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; si_start += 2; } break; default: while (si_start < si_end) { hi_start = fs->scale - 1; while (hi_start >= 0) { tmp[0] = tmp[1] = 0; si = si_start; hi = hi_start; while (hi < hi_end) { tmp[0] += work_buf[si] * h[hi]; tmp[1] += work_buf[si + 1] * h[hi]; hi += fs->scale; si += 2; } tmp[0] /= SINC_SCALE; tmp[1] /= SINC_SCALE; clip16(tmp[0]); clip16(tmp[1]); *out++ = (short)tmp[0]; *out++ = (short)tmp[1]; hi_start--; } si_start += 2; } } assert(si_start == si_end); assert(out == dst + dst_len); block_free(work_buf, work_len * sizeof(sample)); xmemchk(); }