Ejemplo n.º 1
0
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;
}
Ejemplo n.º 2
0
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);
}
Ejemplo n.º 3
0
/* 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;
}
Ejemplo n.º 4
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;
}
Ejemplo n.º 5
0
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);
}
Ejemplo n.º 6
0
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;
        }
}
Ejemplo n.º 7
0
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;
}
Ejemplo n.º 8
0
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;
}
Ejemplo n.º 9
0
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;
}
Ejemplo n.º 10
0
/* 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;

}
Ejemplo n.º 11
0
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;
        }
}
Ejemplo n.º 12
0
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;
}
Ejemplo n.º 13
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;
}
Ejemplo n.º 14
0
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();
        }
}
Ejemplo n.º 15
0
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;
}
Ejemplo n.º 16
0
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();
}
Ejemplo n.º 17
0
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;
}
Ejemplo n.º 18
0
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();
}
Ejemplo n.º 19
0
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;
}