*/
#include <regex.h>
-#include <dirent.h>
#include <osl.h>
#include "para.h"
return 1;
}
+static void vss_get_chunk(int chunk_num, struct vss_task *vsst,
+ char **buf, size_t *sz)
+{
+ /*
+ * Chunk zero is special for header streams: It is the first portion of
+ * the audio file which consists of the audio file header. It may be
+ * arbitrary large due to embedded meta data. Audio format handlers may
+ * replace the header by a stripped one with meta data omitted which is
+ * of bounded size. We always use the stripped header for streaming
+ * rather than the unmodified header (chunk zero).
+ */
+ if (chunk_num == 0 && vsst->header_len > 0) {
+ *buf = vsst->header_buf; /* stripped header */
+ *sz = vsst->header_len;
+ return;
+ }
+ afh_get_chunk(chunk_num, &mmd->afd.afhi, vsst->map, (const char **)buf,
+ sz);
+}
+
static void compute_group_size(struct vss_task *vsst, struct fec_group *g,
int max_bytes)
{
* of exactly one chunk for these audio formats.
*/
for (i = 0;; i++) {
- const char *buf;
+ char *buf;
size_t len;
int chunk_num = g->first_chunk + i;
break;
if (chunk_num >= mmd->afd.afhi.chunks_total) /* eof */
break;
- afh_get_chunk(chunk_num, &mmd->afd.afhi, vsst->map, &buf, &len);
+ vss_get_chunk(chunk_num, vsst, &buf, &len);
if (g->bytes + len > max_bytes)
break;
/* Include this chunk */
{
int ret, i, k, n, data_slices;
size_t len;
- const char *buf;
+ char *buf;
struct fec_group *g = &fc->group;
if (fc->state == FEC_STATE_NONE) {
/* setup header slices */
buf = vsst->header_buf;
for (i = 0; i < g->num_header_slices; i++) {
+ uint32_t payload_size;
if (buf + g->slice_bytes <= vsst->header_buf + vsst->header_len) {
fc->src_data[i] = (const unsigned char *)buf;
buf += g->slice_bytes;
* goes beyond the buffer. This slice will not be fully
* used.
*/
- uint32_t payload_size = vsst->header_buf
- + vsst->header_len - buf;
+ 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,
}
/* setup data slices */
- afh_get_chunk(g->first_chunk, &mmd->afd.afhi, vsst->map, &buf, &len);
+ vss_get_chunk(g->first_chunk, vsst, &buf, &len);
for (; i < g->num_header_slices + data_slices; i++) {
if (buf + g->slice_bytes > vsst->map + mmd->size) {
/*
return ret < 0? 1 : 0;
}
-static void compute_slice_timeout(struct timeval *timeout)
-{
- struct fec_client *fc;
-
- list_for_each_entry(fc, &fec_client_list, node) {
- struct timeval diff;
-
- if (fc->state != FEC_STATE_READY_TO_RUN)
- continue;
- if (next_slice_is_due(fc, &diff)) {
- timeout->tv_sec = 0;
- timeout->tv_usec = 0;
- return;
- }
- /* timeout = min(timeout, diff) */
- if (tv_diff(&diff, timeout, NULL) < 0)
- *timeout = diff;
- }
-}
-
static void set_eof_barrier(struct vss_task *vsst)
{
struct fec_client *fc;
return -1;
}
-/*
- * != NULL: timeout for next chunk
- * NULL: nothing to do
- */
-static struct timeval *vss_compute_timeout(struct vss_task *vsst)
+static void vss_compute_timeout(struct sched *s, struct vss_task *vsst)
{
- static struct timeval the_timeout;
- struct timeval next_chunk;
-
- if (vss_next() && vsst->map) {
- /* only sleep a bit, nec*/
- the_timeout.tv_sec = 0;
- the_timeout.tv_usec = 100;
- return &the_timeout;
- }
- if (chk_barrier("autoplay_delay", &vsst->autoplay_barrier,
- &the_timeout, 1) < 0)
- return &the_timeout;
- if (chk_barrier("eof", &vsst->eof_barrier, &the_timeout, 1) < 0)
- return &the_timeout;
- if (chk_barrier("data send", &vsst->data_send_barrier,
- &the_timeout, 1) < 0)
- return &the_timeout;
+ struct timeval tv;
+ struct fec_client *fc;
+
if (!vss_playing() || !vsst->map)
- return NULL;
+ return;
+ if (vss_next() && vsst->map) /* only sleep a bit, nec*/
+ return sched_request_timeout_ms(100, s);
+
+ /* Each of these barriers must have passed until we may proceed */
+ if (sched_request_barrier(&vsst->autoplay_barrier, s) == 1)
+ return;
+ if (sched_request_barrier(&vsst->eof_barrier, s) == 1)
+ return;
+ if (sched_request_barrier(&vsst->data_send_barrier, s) == 1)
+ return;
+ /*
+ * Compute the select timeout as the minimal time until the next
+ * chunk/slice is due for any client.
+ */
compute_chunk_time(mmd->chunks_sent, &mmd->afd.afhi.chunk_tv,
- &mmd->stream_start, &next_chunk);
- if (chk_barrier("chunk", &next_chunk, &the_timeout, 0) >= 0) {
- /* chunk is due or bof */
- the_timeout.tv_sec = 0;
- the_timeout.tv_usec = 0;
- return &the_timeout;
+ &mmd->stream_start, &tv);
+ if (sched_request_barrier_or_min_delay(&tv, s) == 0)
+ return;
+ list_for_each_entry(fc, &fec_client_list, node) {
+ if (fc->state != FEC_STATE_READY_TO_RUN)
+ continue;
+ if (next_slice_is_due(fc, &tv))
+ return sched_min_delay(s);
+ sched_request_timeout(&tv, s);
}
- /* compute min of current timeout and next slice time */
- compute_slice_timeout(&the_timeout);
- return &the_timeout;
}
static void vss_eof(struct vss_task *vsst)
static void vss_pre_select(struct sched *s, struct task *t)
{
int i;
- struct timeval *tv;
struct vss_task *vsst = container_of(t, struct vss_task, task);
if (!vsst->map || vss_next() || vss_paused() || vss_repos()) {
continue;
senders[i].pre_select(&s->max_fileno, &s->rfds, &s->wfds);
}
- tv = vss_compute_timeout(vsst);
- if (tv)
- sched_request_timeout(tv, s);
+ vss_compute_timeout(s, vsst);
}
static int recv_afs_msg(int afs_socket, int *fd, uint32_t *code, uint32_t *data)
compute_chunk_time(mmd->chunks_sent, &mmd->afd.afhi.chunk_tv,
&mmd->stream_start, &due);
if (tv_diff(&due, now, NULL) <= 0) {
- const char *buf;
+ char *buf;
size_t len;
if (!mmd->chunks_sent) {
* they might have still some data queued which can be sent in
* this case.
*/
- afh_get_chunk(mmd->current_chunk, &mmd->afd.afhi, vsst->map,
- &buf, &len);
+ vss_get_chunk(mmd->current_chunk, vsst, &buf, &len);
for (i = 0; senders[i].name; i++) {
if (!senders[i].send)
continue;
tv_add(&vsst->autoplay_barrier, &vsst->announce_tv,
&vsst->data_send_barrier);
}
+ sprintf(vsst->task.status, "vss task");
register_task(&vsst->task);
}