+static int initialize_fec_client(struct fec_client *fc, struct vss_task *vsst)
+{
+ int k, n, ret, mps;
+ int hs, ds, rs; /* header/data/redundant slices */
+ struct fec_client_parms *fcp = fc->fcp;
+
+ /* set mps */
+ if (fcp->init_fec) {
+ /*
+ * Set the maximum slice size to the Maximum Packet Size if the
+ * transport protocol allows to determine this value. The user
+ * can specify a slice size up to this value.
+ */
+ ret = fcp->init_fec(fc->sc);
+ if (ret < 0)
+ return ret;
+ mps = ret;
+ } else
+ mps = generic_max_transport_msg_size(fc->sc->fd);
+ if (mps <= FEC_HEADER_SIZE)
+ return -ERRNO_TO_PARA_ERROR(EINVAL);
+
+ rs = fc->fcp->slices_per_group - fc->fcp->data_slices_per_group;
+ ret = num_slices(vsst->header_len, mps, rs);
+ if (ret < 0)
+ goto err;
+ hs = ret;
+ ret = num_slices(mmd->afd.max_chunk_size, mps, rs);
+ if (ret < 0)
+ goto err;
+ ds = ret;
+ k = ret + ds;
+ if (k < fc->fcp->data_slices_per_group)
+ k = fc->fcp->data_slices_per_group;
+ n = k + rs;
+ PARA_CRIT_LOG("hs: %d, ds: %d, rs: %d, k: %d, n: %d\n", hs, ds, rs, k, n);
+ fec_free(fc->parms);
+ ret = fec_new(k, n, &fc->parms);
+ if (ret < 0)
+ return ret;
+ fc->num_extra_slices = k - fc->fcp->data_slices_per_group;
+ PARA_NOTICE_LOG("fec parms %d:%d:%d (%d extra slices)\n",
+ mps, k, n, fc->num_extra_slices);
+ fc->src_data = para_realloc(fc->src_data, k * sizeof(char *));
+ fc->enc_buf = para_realloc(fc->enc_buf, mps);
+ memset(fc->enc_buf, 0, mps);
+ fc->extra_src_buf = para_realloc(fc->extra_src_buf, mps);
+ memset(fc->extra_src_buf, 0, mps);
+
+ fc->mps = mps;
+ fc->state = FEC_STATE_READY_TO_RUN;
+ fc->next_header_time.tv_sec = 0;
+ fc->stream_start = *now;
+ fc->first_stream_chunk = mmd->current_chunk;
+ return 1;
+err:
+ fec_free(fc->parms);
+ return ret;
+}
+
+static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst)
+{
+ int ret, i, k, n, data_slices;
+ size_t len;
+ const char *buf, *start_buf;
+ struct fec_group *g = &fc->group;
+ unsigned slice_bytes;
+ uint32_t max_data_size;
+
+ if (fc->state == FEC_STATE_NONE) {
+ ret = initialize_fec_client(fc, vsst);
+ if (ret < 0)
+ return ret;
+ g->first_chunk = mmd->current_chunk;
+ g->num = 0;
+ g->start = *now;
+
+ } else {
+ struct timeval tmp;
+ if (g->first_chunk + g->num_chunks >= mmd->afd.afhi.chunks_total)
+ return 0;
+ /*
+ * Start and duration of this group depend only on the previous
+ * group. Compute the new group start as g->start += g->duration.
+ */
+ tmp = g->start;
+ tv_add(&tmp, &g->duration, &g->start);
+ set_group_timing(fc, g);
+ g->first_chunk += g->num_chunks;
+ g->num++;
+ }
+ slice_bytes = fc->mps - FEC_HEADER_SIZE;
+ PARA_CRIT_LOG("slice_bytes: %d\n", slice_bytes);
+ k = fc->fcp->data_slices_per_group + fc->num_extra_slices;
+ n = fc->fcp->slices_per_group + fc->num_extra_slices;
+ PARA_CRIT_LOG("k: %d, n: %d\n", k, n);
+ if (need_audio_header(fc, vsst)) {
+ ret = num_slices(vsst->header_len, slice_bytes, n - k);
+ if (ret < 0)
+ return ret;
+ g->num_header_slices = ret;
+ } else
+ g->num_header_slices = 0;
+ afh_get_chunk(g->first_chunk, &mmd->afd.afhi, vsst->map, &start_buf,
+ &len);
+ data_slices = k - g->num_header_slices;
+ assert(data_slices);
+ max_data_size = slice_bytes * data_slices;
+ g->bytes = 0;
+ for (i = g->first_chunk; i < mmd->afd.afhi.chunks_total; i++) {
+ afh_get_chunk(i, &mmd->afd.afhi, vsst->map, &buf, &len);
+ if (g->bytes + len > max_data_size)
+ break;
+ g->bytes += len;
+ }
+ g->num_chunks = i - g->first_chunk;
+ assert(g->num_chunks);
+ fc->current_slice_num = 0;
+ if (g->num == 0)
+ set_group_timing(fc, g);
+
+ /* setup header slices */
+ buf = vsst->header_buf;
+ for (i = 0; i < g->num_header_slices; i++) {
+ fc->src_data[i] = (const unsigned char *)buf;
+ buf += slice_bytes;
+ }
+
+ /* setup data slices */
+ buf = start_buf;
+ for (i = g->num_header_slices; i < k; i++) {
+ if (buf + slice_bytes > vsst->map + mmd->size)
+ /*
+ * Can not use the memory mapped audio file for this
+ * slice as it goes beyond the map. This slice will not
+ * be fully used.
+ */
+ break;
+ fc->src_data[i] = (const unsigned char *)buf;
+ buf += slice_bytes;
+ }
+ if (i < k) {
+ uint32_t payload_size = vsst->map + mmd->size - buf;
+ memcpy(fc->extra_src_buf, buf, payload_size);
+ fc->src_data[i] = fc->extra_src_buf;
+ i++;
+ /* use arbitrary data for all remaining slices */
+ buf = vsst->map;
+ for (; i < k; i++)
+ fc->src_data[i] = (const unsigned char *)buf;
+ }
+ PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), "
+ "%d header slices, %d data slices\n",
+ g->num, g->num_chunks, g->first_chunk,
+ g->first_chunk + g->num_chunks - 1,
+ g->num_header_slices, data_slices
+ );
+ return 1;
+}