return 1;
}
+static void set_slice_duration(struct fec_client *fc, struct fec_group *g)
+{
+ struct timeval group_duration, *chunk_tv = vss_chunk_time();
+
+ tv_scale(g->num_chunks, chunk_tv, &group_duration);
+ tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices,
+ &group_duration, &g->slice_duration);
+ PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n",
+ tv2ms(&group_duration), tv2ms(chunk_tv), tv2ms(&g->slice_duration));
+}
+
static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst)
{
int ret, i, k, data_slices;
uint32_t max_data_size;
assert(chunk_tv);
- k = fc->fcp->data_slices_per_group + fc->num_extra_slices;
if (fc->first_stream_chunk < 0) {
- uint32_t largest = afh_get_largest_chunk_size(&mmd->afd.afhi)
- + vsst->header_len;
- uint8_t needed, want;
+ uint8_t hs, ds; /* needed header/data slices */
+ uint8_t rs = fc->fcp->slices_per_group
+ - fc->fcp->data_slices_per_group; /* redundant slices */
+ int n;
- ret = num_slices(largest, fc, &needed);
+ ret = num_slices(vsst->header_len, fc, &hs);
+ if (ret < 0)
+ return ret;
+ ret = num_slices(afh_get_largest_chunk_size(&mmd->afd.afhi),
+ fc, &ds);
+ if (ret < 0)
+ return ret;
+ k = (int)hs + ds;
+ if (k > 255)
+ return -E_BAD_CT;
+ if (k < fc->fcp->data_slices_per_group)
+ k = fc->fcp->data_slices_per_group;
+ n = k + rs;
+ fc->num_extra_slices = k - fc->fcp->data_slices_per_group;
+ PARA_NOTICE_LOG("fec parms %d:%d:%d (%d extra slices)\n",
+ slice_bytes, k, n, fc->num_extra_slices);
+ fec_free(fc->parms);
+ fc->src_data = para_realloc(fc->src_data, k * sizeof(char *));
+ ret = fec_new(k, n, &fc->parms);
if (ret < 0)
return ret;
- if (needed > fc->fcp->data_slices_per_group)
- PARA_WARNING_LOG("fec parms insufficient for this audio file\n");
- want = PARA_MAX(needed, fc->fcp->data_slices_per_group);
- if (want != k) {
- fec_free(fc->parms);
- fc->src_data = para_realloc(fc->src_data, want * sizeof(char *));
- ret = fec_new(want, want + fc->fcp->slices_per_group
- - fc->fcp->data_slices_per_group, &fc->parms);
- if (ret < 0)
- return ret;
- k = want;
- fc->num_extra_slices = 0;
- if (k > fc->fcp->data_slices_per_group) {
- fc->num_extra_slices = k - fc->fcp->data_slices_per_group;
- PARA_NOTICE_LOG("using %d extra slices\n",
- fc->num_extra_slices);
- }
- }
fc->stream_start = *now;
fc->first_stream_chunk = mmd->current_chunk;
g->first_chunk = mmd->current_chunk;
g->num = 0;
} else {
+ k = fc->fcp->data_slices_per_group + fc->num_extra_slices;
+ /* use duration of the previous group for the timing of this group */
+ set_slice_duration(fc, g);
g->first_chunk += g->num_chunks;
g->num++;
}
g->num_chunks = i - g->first_chunk;
assert(g->num_chunks);
fc->current_slice_num = 0;
+ if (g->num == 0)
+ set_slice_duration(fc, g);
/* setup header slices */
buf = vsst->header_buf;
for (; i < k; i++)
fc->src_data[i] = (const unsigned char *)buf;
}
-
- /* setup group timing */
- tv_scale(g->first_chunk - fc->first_stream_chunk, chunk_tv, &tmp);
- tv_add(&fc->stream_start, &tmp, &g->start);
- if (g->num) /* quick hack to avoid buffer underruns */
- g->start.tv_sec--;
- tv_scale(g->num_chunks, chunk_tv, &tmp); /* group duration */
- tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices,
- &tmp, &g->slice_duration);
-
- PARA_DEBUG_LOG("FEC group %d: %d chunks (%d - %d), %d header slices, %d data slices\n",
+ 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
);
- PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n",
- tv2ms(&tmp), tv2ms(chunk_tv), tv2ms(&g->slice_duration));
+ /* set group start */
+ if (g->num != 0 && vsst->header_len != 0 && fc->first_stream_chunk == 0)
+ /* chunk #0 is the audio file header */
+ tv_scale(g->first_chunk - 1, chunk_tv, &tmp);
+ else
+ tv_scale(g->first_chunk - fc->first_stream_chunk,
+ chunk_tv, &tmp);
+ tv_add(&fc->stream_start, &tmp, &g->start);
return 1;
}
*/
static void vss_send(struct vss_task *vsst)
{
- int i, sent_something = 0;
+ int i, fec_active = 0;
struct timeval due;
struct fec_client *fc, *tmp_fc;
list_for_each_entry_safe(fc, tmp_fc, &fec_client_list, node) {
if (fc->error < 0)
continue;
- if (!next_slice_is_due(fc, NULL))
+ if (!next_slice_is_due(fc, NULL)) {
+ fec_active = 1;
continue;
+ }
if (compute_next_fec_slice(fc, vsst) <= 0)
continue;
PARA_DEBUG_LOG("sending %d:%d (%u bytes)\n", fc->group.num,
fc->fcp->max_slice_bytes,
fc->fcp->private_data);
fc->current_slice_num++;
- sent_something = 1;
+ fec_active = 1;
}
if (mmd->current_chunk >= mmd->afd.afhi.chunks_total) { /* eof */
- if (!sent_something)
+ if (!fec_active)
mmd->new_vss_status_flags |= VSS_NEXT;
return;
}