/*
- * Copyright (C) 1997-2010 Andre Noll <maan@systemlinux.org>
+ * Copyright (C) 1997-2011 Andre Noll <maan@systemlinux.org>
*
* Licensed under the GPL v2. For licencing details see COPYING.
*/
/** Used by the scheduler. */
struct task task;
/** Pointer to the header of the mapped audio file. */
- const char *header_buf;
+ char *header_buf;
/** Length of the audio file header. */
size_t header_len;
/** Time between audio file headers are sent. */
struct timeval next_header_time;
/** Used for the last source pointer of an audio file. */
unsigned char *extra_src_buf;
+ /** Needed for the last slice of the audio file header. */
+ unsigned char *extra_header_buf;
/** Extra slices needed to store largest chunk + header. */
int num_extra_slices;
/** Contains the FEC-encoded data. */
write_u32(buf + 14, g->bytes);
write_u8(buf + 18, fc->current_slice_num);
+ write_u8(buf + 19, 0); /* unused */
write_u16(buf + 20, g->slice_bytes);
write_u8(buf + 22, g->first_chunk? 0 : 1);
write_u8(buf + 23, vsst->header_len? 1 : 0);
- memset(buf + 24, 0, 7);
+ memset(buf + 24, 0, 8);
}
static bool need_audio_header(struct fec_client *fc, struct vss_task *vsst)
return false;
if (vsst->header_len == 0)
return false;
- if (fc->group.num && tv_diff(&fc->next_header_time, now, NULL) > 0)
- return false;
+ if (fc->group.num > 0) {
+ if (!fc->fcp->need_periodic_header)
+ return false;
+ if (tv_diff(&fc->next_header_time, now, NULL) > 0)
+ return false;
+ }
tv_add(now, &vsst->header_interval, &fc->next_header_time);
return true;
}
+static bool need_data_slices(struct fec_client *fc, struct vss_task *vsst)
+{
+ if (fc->group.num > 0)
+ return true;
+ if (!vsst->header_buf)
+ return true;
+ if (vsst->header_len == 0)
+ return true;
+ if (fc->fcp->need_periodic_header)
+ return true;
+ return false;
+}
+
static int num_slices(long unsigned bytes, int max_payload, int rs)
{
int ret;
}
/* set group start and group duration */
-static void set_group_timing(struct fec_client *fc, struct fec_group *g)
+static void set_group_timing(struct fec_client *fc, struct vss_task *vsst)
{
+ struct fec_group *g = &fc->group;
struct timeval *chunk_tv = vss_chunk_time();
- tv_scale(g->num_chunks, chunk_tv, &g->duration);
+ if (!need_data_slices(fc, vsst))
+ ms2tv(200, &g->duration);
+ else
+ tv_scale(g->num_chunks, chunk_tv, &g->duration);
tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices,
&g->duration, &g->slice_duration);
PARA_DEBUG_LOG("durations (group/chunk/slice): %lu/%lu/%lu\n",
rs = fc->fcp->slices_per_group - fc->fcp->data_slices_per_group;
ret = num_slices(vsst->header_len, fc->mps - FEC_HEADER_SIZE, rs);
if (ret < 0)
- goto err;
+ return ret;
hs = ret;
ret = num_slices(mmd->afd.max_chunk_size, fc->mps - FEC_HEADER_SIZE, rs);
if (ret < 0)
- goto err;
+ return ret;
ds = ret;
- k = hs + ds;
+ if (fc->fcp->need_periodic_header)
+ k = hs + ds;
+ else
+ k = PARA_MAX(hs, ds);
if (k < fc->fcp->data_slices_per_group)
k = fc->fcp->data_slices_per_group;
fc->num_extra_slices = k - fc->fcp->data_slices_per_group;
fc->src_data = para_realloc(fc->src_data, k * sizeof(char *));
fc->enc_buf = para_realloc(fc->enc_buf, fc->mps);
fc->extra_src_buf = para_realloc(fc->extra_src_buf, fc->mps);
+ fc->extra_header_buf = para_realloc(fc->extra_header_buf, fc->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 void compute_group_size(struct vss_task *vsst, struct fec_group *g,
g->slice_bytes = 1;
return 1;
}
+ if (!need_data_slices(fc, vsst)) {
+ g->bytes = 0;
+ g->num_chunks = 0;
+ g->slice_bytes = DIV_ROUND_UP(vsst->header_len, k);
+ g->num_header_slices = k;
+ return 1;
+ }
h = vsst->header_len;
max_group_bytes = (k - num_slices(h, max_slice_bytes, n - k))
* max_slice_bytes;
*/
tmp = g->start;
tv_add(&tmp, &g->duration, &g->start);
- set_group_timing(fc, g);
+ set_group_timing(fc, vsst);
g->first_chunk += g->num_chunks;
g->num++;
}
assert(g->num_header_slices + data_slices <= k);
fc->current_slice_num = 0;
if (g->num == 0)
- set_group_timing(fc, g);
-
+ set_group_timing(fc, vsst);
/* 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 += g->slice_bytes;
+ if (buf + g->slice_bytes <= vsst->header_buf + vsst->header_len) {
+ fc->src_data[i] = (const unsigned char *)buf;
+ buf += g->slice_bytes;
+ continue;
+ }
+ /*
+ * Can not use vss->header_buf for this slice as it
+ * goes beyond the buffer. This slice will not be fully
+ * used.
+ */
+ uint32_t payload_size = vsst->header_buf
+ + vsst->header_len - buf;
+ memcpy(fc->extra_header_buf, buf, payload_size);
+ if (payload_size < g->slice_bytes)
+ memset(fc->extra_header_buf + payload_size, 0,
+ g->slice_bytes - payload_size);
+ fc->src_data[i] = fc->extra_header_buf;
+ assert(i == g->num_header_slices - 1);
}
/* setup data slices */
if (buf + g->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.
+ * slice as it goes beyond the map.
*/
uint32_t payload_size = vsst->map + mmd->size - buf;
memcpy(fc->extra_src_buf, buf, payload_size);
free(fc->src_data);
free(fc->enc_buf);
free(fc->extra_src_buf);
+ free(fc->extra_header_buf);
fec_free(fc->parms);
free(fc);
}
if (mmd->new_vss_status_flags & VSS_NOMORE)
mmd->new_vss_status_flags = VSS_NEXT;
set_eof_barrier(vsst);
+ afh_free_header(vsst->header_buf, mmd->afd.audio_format_id);
+ vsst->header_buf = NULL;
para_munmap(vsst->map, mmd->size);
vsst->map = NULL;
mmd->chunks_sent = 0;
mmd->events++;
mmd->num_played++;
mmd->new_vss_status_flags &= (~VSS_NEXT);
- afh_get_header(&mmd->afd.afhi, vsst->map, &vsst->header_buf,
- &vsst->header_len);
+ afh_get_header(&mmd->afd.afhi, mmd->afd.audio_format_id,
+ vsst->map, mmd->size, &vsst->header_buf, &vsst->header_len);
return;
err:
free(mmd->afd.afhi.chunk_table);