From: Andre Noll Date: Sun, 17 Jan 2010 20:32:11 +0000 (+0100) Subject: Merge remote branch 'athcx/maint' into maint X-Git-Tag: v0.4.2~13^2~3 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=4e84e9b35b8e45314d779ff6353e826ebda31483;hp=40af26f7f363ee8806874c470cd6338f4f934efa Merge remote branch 'athcx/maint' into maint --- diff --git a/Makefile.in b/Makefile.in index b4392a3c..d04d0ea3 100644 --- a/Makefile.in +++ b/Makefile.in @@ -13,7 +13,7 @@ build_date := $(shell date) uname_s := $(shell uname -s 2>/dev/null || echo "UNKNOWN_OS") uname_rs := $(shell uname -rs) cc_version := $(shell $(CC) --version | head -n 1) -codename := symplectic separability +codename := imaginary radiation DEBUG_CPPFLAGS += -Wno-sign-compare -g -Wunused -Wundef -W DEBUG_CPPFLAGS += -Wredundant-decls diff --git a/NEWS b/NEWS index 52d2b7cb..66ce1f3f 100644 --- a/NEWS +++ b/NEWS @@ -1,6 +1,24 @@ NEWS ==== +------------------------------------- +0.3.6 (2009-12-07) "cubic continuity" +------------------------------------- + +Quite a few bugs have been found and fixed since 0.3.5, so here's +another 0.3.x release. No new features. + + - Always check return value of malloc(). + - ogg vorbis/FEC: Do not write garbage after the audio file header. + - exit if root privileges could not be dropped. + - FEC: Fix computation of extra slices. + - oss: Fix check for empty input buffer. + - Avoid buffer underruns due to filter chain output buffer constraints. + - server: Fix assignment of afs_pid. + - Don't panic if the afs database contains unknown audio formats. + - http/dccp: Do not send the audio file header twice. + - FEC: Timing improvements. + -------------------------------------------- 0.3.5 (2009-09-21) "symplectic separability" -------------------------------------------- diff --git a/afh_common.c b/afh_common.c index 8c0eed27..7d4ab089 100644 --- a/afh_common.c +++ b/afh_common.c @@ -208,9 +208,9 @@ int compute_afhi(const char *path, char *data, size_t size, int fd, */ const char *audio_format_name(int i) { - //PARA_NOTICE_LOG("array size: %u¸ requested: %d\n", ARRAY_SIZE(afl), i); - assert(i < 0 || i < ARRAY_SIZE(afl) - 1); - return i >= 0? afl[i].name : "(none)"; + if (i < 0 || i >= ARRAY_SIZE(afl) - 1) + return "???"; + return afl[i].name; } /** diff --git a/alsa_write.c b/alsa_write.c index d7828945..53c97384 100644 --- a/alsa_write.c +++ b/alsa_write.c @@ -79,18 +79,19 @@ static int alsa_init(struct private_alsa_write_data *pad, pad->channels) < 0) return -E_CHANNEL_COUNT; if (snd_pcm_hw_params_set_rate_near(pad->handle, hwparams, - &pad->samplerate, 0) < 0) + &pad->samplerate, NULL) < 0) return -E_SET_RATE; - err = snd_pcm_hw_params_get_buffer_time_max(hwparams, &pad->buffer_time, 0); + err = snd_pcm_hw_params_get_buffer_time_max(hwparams, + &pad->buffer_time, NULL); if (err < 0 || !pad->buffer_time) return -E_GET_BUFFER_TIME; PARA_INFO_LOG("buffer time: %d\n", pad->buffer_time); if (snd_pcm_hw_params_set_buffer_time_near(pad->handle, hwparams, - &pad->buffer_time, 0) < 0) + &pad->buffer_time, NULL) < 0) return -E_SET_BUFFER_TIME; if (snd_pcm_hw_params(pad->handle, hwparams) < 0) return -E_HW_PARAMS; - snd_pcm_hw_params_get_period_size(hwparams, &period_size, 0); + snd_pcm_hw_params_get_period_size(hwparams, &period_size, NULL); snd_pcm_hw_params_get_buffer_size(hwparams, &buffer_size); PARA_INFO_LOG("buffer size: %lu, period_size: %lu\n", buffer_size, period_size); diff --git a/audiod.c b/audiod.c index d39f0f57..8fbd0a00 100644 --- a/audiod.c +++ b/audiod.c @@ -311,6 +311,7 @@ static void close_receiver(int slot_num) a->receiver->close(s->receiver_node); free(s->receiver_node); s->receiver_node = NULL; + stat_task->current_audio_format_num = -1; } static void kill_all_decoders(int error) @@ -949,6 +950,7 @@ static void close_stat_pipe(void) stat_task->length_seconds = 0; stat_task->offset_seconds = 0; stat_task->vss_status = 0; + stat_task->current_audio_format_num = -1; audiod_status_dump(); } diff --git a/blob.c b/blob.c index 92332272..5ab5c1ce 100644 --- a/blob.c +++ b/blob.c @@ -477,7 +477,7 @@ static int blob_get_name_and_def_by_row(struct osl_table *table, /** Define the \p close function for this blob type. */ #define DEFINE_BLOB_CLOSE(table_name) \ - void table_name ## _close(void) \ + static void table_name ## _close(void) \ { \ osl_close_table(table_name ## _table, OSL_MARK_CLEAN); \ table_name ## _table = NULL; \ @@ -485,7 +485,7 @@ static int blob_get_name_and_def_by_row(struct osl_table *table, /** Define the \p create function for this blob type. */ #define DEFINE_BLOB_CREATE(table_name) \ - int table_name ## _create(const char *dir) \ + static int table_name ## _create(const char *dir) \ { \ table_name ## _table_desc.dir = dir; \ return osl_create_table(&table_name ## _table_desc); \ @@ -507,7 +507,7 @@ static int blob_open(struct osl_table **table, } #define DEFINE_BLOB_OPEN(table_name) \ - int table_name ## _open(const char *dir) \ + static int table_name ## _open(const char *dir) \ { \ return blob_open(&table_name ## _table, \ &table_name ## _table_desc, dir); \ diff --git a/configure.ac b/configure.ac index 85a32729..74a3c742 100644 --- a/configure.ac +++ b/configure.ac @@ -498,7 +498,7 @@ AC_CHECK_HEADER(sys/soundcard.h, [ ], [ have_oss="no" - AC_MSG_WARN([no linux/soundcard.h $msg]) + AC_MSG_WARN([no sys/soundcard.h $msg]) ] ) CPPFLAGS="$OLD_CPPFLAGS" diff --git a/daemon.c b/daemon.c index 3bcb6e01..011ece6d 100644 --- a/daemon.c +++ b/daemon.c @@ -269,7 +269,11 @@ void drop_privileges_or_die(const char *username, const char *groupname) exit(EXIT_FAILURE); } PARA_INFO_LOG("dropping root privileges\n"); - setuid(p->pw_uid); + if (setuid(p->pw_uid) < 0) { + PARA_EMERG_LOG("failed to set effective user ID (%s)", + strerror(errno)); + exit(EXIT_FAILURE); + } PARA_DEBUG_LOG("uid: %d, euid: %d\n", (int)getuid(), (int)geteuid()); } @@ -327,7 +331,7 @@ __printf_2_3 void para_log(int ll, const char* fmt,...) FILE *fp; struct tm *tm; time_t t1; - char *color, str[MAXLINE] = ""; + char *color; ll = PARA_MIN(ll, NUM_LOGLEVELS - 1); ll = PARA_MAX(ll, LL_DEBUG); @@ -338,11 +342,11 @@ __printf_2_3 void para_log(int ll, const char* fmt,...) color = daemon_test_flag(DF_COLOR_LOG)? me->log_colors[ll] : NULL; if (color) fprintf(fp, "%s", color); - if (daemon_test_flag(DF_LOG_TIME)) { - /* date and time */ + if (daemon_test_flag(DF_LOG_TIME)) { /* print date and time */ + char str[100]; time(&t1); tm = localtime(&t1); - strftime(str, MAXLINE, "%b %d %H:%M:%S", tm); + strftime(str, sizeof(str), "%b %d %H:%M:%S", tm); fprintf(fp, "%s ", str); } if (daemon_test_flag(DF_LOG_HOSTNAME)) { diff --git a/fecdec_filter.c b/fecdec_filter.c index a7290e6a..8cb17ad6 100644 --- a/fecdec_filter.c +++ b/fecdec_filter.c @@ -70,20 +70,6 @@ struct fecdec_group { unsigned char **data; }; -/** - * The fecdec filter defers decoding of the first group until the first slice - * of the next group was received. This avoids buffer underruns in subsequent - * filters of the filter chain. - */ -enum group_completion_status { - /** No complete group received so far. */ - GCS_NO_COMPLETE_GROUP, - /** First group received, but not yet decoded. */ - GCS_FIRST_GROUP_COMPLETE, - /** At least one complete group decoded. */ - GCS_FIRST_GROUP_DECODED, -}; - /** * Data private to the fecdec filter. */ @@ -94,15 +80,13 @@ struct private_fecdec_data { struct fecdec_group groups[NUM_FEC_GROUPS]; /** Whether an audio file header was already received. */ int have_header; - /** See \ref group_completion_status. */ - unsigned completion_status; /** Points to the first received group. */ struct fecdec_group *first_complete_group; }; /** Iterate over all fecdec groups. */ #define FOR_EACH_FECDEC_GROUP(g, d) for (g = (d)->groups; \ - (g) - (d)->groups < NUM_FEC_GROUPS; (g)++) + (g) < (d)->groups + NUM_FEC_GROUPS; (g)++) static int group_complete(struct fecdec_group *fg) { @@ -124,7 +108,9 @@ static void clear_group(struct fecdec_group *fg) fg->idx[i] = -1; } free(fg->data); + fg->data = NULL; free(fg->idx); + fg->idx = NULL; fg->num_slices = 0; memset(&fg->h, 0, sizeof(struct fec_header)); fg->num_received_slices = 0; @@ -175,8 +161,7 @@ static struct fecdec_group *try_to_free_group(struct private_fecdec_data *pfd) * Don't clear the first complete group if it has not yet been * decoded. */ - if (pfd->completion_status == GCS_FIRST_GROUP_COMPLETE - && pfd->first_complete_group == fg) + if (fg == pfd->first_complete_group) continue; clear_group(fg); return fg; @@ -196,8 +181,8 @@ static struct fecdec_group *free_oldest_group(struct private_fecdec_data *pfd) PARA_WARNING_LOG("Clearing incomplete group %d " "(contains %d slices)\n", oldest->h.group_num, oldest->num_received_slices); - assert(pfd->completion_status != GCS_FIRST_GROUP_COMPLETE - || oldest != pfd->first_complete_group); + if (oldest == pfd->first_complete_group) + pfd->first_complete_group = NULL; clear_group(oldest); return oldest; } @@ -262,6 +247,7 @@ enum fec_group_usability { FEC_GROUP_UNUSABLE, FEC_GROUP_USABLE, FEC_GROUP_USABLE_SKIP_HEADER, + FEC_GROUP_USABLE_WITH_HEADER }; static enum fec_group_usability group_is_usable(struct fecdec_group *fg, @@ -279,14 +265,14 @@ static enum fec_group_usability group_is_usable(struct fecdec_group *fg, if (fg->h.bos) return FEC_GROUP_USABLE; if (fg->h.audio_header_size) - return FEC_GROUP_USABLE; + return FEC_GROUP_USABLE_WITH_HEADER; return FEC_GROUP_UNUSABLE; } static int decode_group(struct fecdec_group *fg, struct filter_node *fn) { int i, ret, sb = fg->h.slice_bytes; - size_t written = 0, need; + size_t written, need; struct private_fecdec_data *pfd = fn->private_data; enum fec_group_usability u = group_is_usable(fg, pfd); @@ -317,6 +303,21 @@ static int decode_group(struct fecdec_group *fg, struct filter_node *fn) PARA_INFO_LOG("increasing fec buf to %zu\n", fn->bufsize); fn->buf = para_realloc(fn->buf, fn->bufsize); } + if (u == FEC_GROUP_USABLE_WITH_HEADER) { + PARA_INFO_LOG("writing audio file header\n"); + written = 0; + for (i = 0; i < fg->h.data_slices_per_group; i++) { + size_t n = sb; + if (written >= fg->h.audio_header_size) + break; + if (sb + written > fg->h.audio_header_size) + n = fg->h.audio_header_size - written; + memcpy(fn->buf + fn->loaded, fg->data[i], n); + fn->loaded += n; + written += n; + } + } + written = 0; for (; i < fg->h.data_slices_per_group; i++) { size_t n = sb; if (n + written > fg->h.group_bytes) @@ -374,37 +375,39 @@ static int dispatch_slice(char *buf, size_t len, struct fec_header *h, ret = get_group(h, pfd, &fg); if (ret < 0) return ret; - if (!add_slice(buf, fg)) + if (!add_slice(buf, fg)) /* group already complete */ return 1; - if (group_complete(fg)) { - if (pfd->completion_status == GCS_NO_COMPLETE_GROUP) { - pfd->completion_status = GCS_FIRST_GROUP_COMPLETE; - pfd->first_complete_group = fg; + if (!group_complete(fg)) + return 1; + /* this slice completed the group */ + if (pfd->fec) + goto decode; + /* it's either the first or the second complete group */ + if (!pfd->first_complete_group) { /* it's the first group */ + enum fec_group_usability u = group_is_usable(fg, pfd); + assert(u != FEC_GROUP_USABLE_SKIP_HEADER); + if (u == FEC_GROUP_UNUSABLE) /* forget it */ return 1; - } - assert(pfd->fec); - ret = decode_group(fg, fn); - if (ret < 0) - return ret; + pfd->first_complete_group = fg; /* remember it */ return 1; } - if (pfd->completion_status == GCS_NO_COMPLETE_GROUP) - return 1; - if (pfd->completion_status == GCS_FIRST_GROUP_DECODED) - return 1; - if (fg == pfd->first_complete_group) - return 1; - assert(!pfd->fec); + /* we have two complete groups, let's go */ k = h->data_slices_per_group; n = h->slices_per_group; PARA_NOTICE_LOG("init fec (%d, %d)\n", k, n); ret = fec_new(k, n, &pfd->fec); if (ret < 0) return ret; + /* decode and clear the first group */ ret = decode_group(pfd->first_complete_group, fn); if (ret < 0) return ret; - pfd->completion_status = GCS_FIRST_GROUP_DECODED; + clear_group(pfd->first_complete_group); + pfd->first_complete_group = NULL; +decode: + ret = decode_group(fg, fn); + if (ret < 0) + return ret; return 1; } @@ -448,7 +451,6 @@ static void fecdec_open(struct filter_node *fn) fn->bufsize = FECDEC_DEFAULT_OUTBUF_SIZE; fn->buf = para_malloc(fn->bufsize); pfd = para_calloc(sizeof(*pfd)); - pfd->completion_status = GCS_NO_COMPLETE_GROUP; fn->private_data = pfd; fn->loaded = 0; } diff --git a/http_send.c b/http_send.c index 5b98bbf4..0c48934a 100644 --- a/http_send.c +++ b/http_send.c @@ -133,7 +133,7 @@ static void http_post_select(fd_set *rfds, __a_unused fd_set *wfds) phsd->status = HTTP_CONNECTED; } -static void http_pre_select(int *max_fileno, fd_set *rfds, __a_unused fd_set *wfds) +static void http_pre_select(int *max_fileno, fd_set *rfds, fd_set *wfds) { struct sender_client *sc, *tmp; @@ -144,6 +144,9 @@ static void http_pre_select(int *max_fileno, fd_set *rfds, __a_unused fd_set *wf struct private_http_sender_data *phsd = sc->private_data; if (phsd->status == HTTP_CONNECTED) /* need to recv get request */ para_fd_set(sc->fd, rfds, max_fileno); + if (phsd->status == HTTP_GOT_GET_REQUEST || + phsd->status == HTTP_INVALID_GET_REQUEST) + para_fd_set(sc->fd, wfds, max_fileno); } } diff --git a/oss_write.c b/oss_write.c index 6a55005e..3ef0d9e8 100644 --- a/oss_write.c +++ b/oss_write.c @@ -47,13 +47,13 @@ static int oss_pre_select(struct sched *s, struct writer_node *wn) struct private_oss_write_data *powd = wn->private_data; struct writer_node_group *wng = wn->wng; - if (!*wng->loaded) + if (*wng->loaded - wn->written < powd->bytes_per_frame) return 0; para_fd_set(powd->fd, &s->wfds, &s->max_fileno); return 1; } -static int oss_post_select(__a_unused struct sched *s, - struct writer_node *wn) + +static int oss_post_select(struct sched *s, struct writer_node *wn) { int ret; struct private_oss_write_data *powd = wn->private_data; diff --git a/osx_write.c b/osx_write.c index aa95d383..c4042889 100644 --- a/osx_write.c +++ b/osx_write.c @@ -13,7 +13,7 @@ #include #include -#include + #include "para.h" #include "fd.h" #include "string.h" @@ -24,10 +24,9 @@ #include "osx_write.cmdline.h" #include "error.h" - -#include +#include #include -#include +#include /** describes one input buffer for the osx writer */ struct osx_buffer { diff --git a/send_common.c b/send_common.c index 200e59ab..8653c330 100644 --- a/send_common.c +++ b/send_common.c @@ -159,8 +159,8 @@ void send_chunk(struct sender_client *sc, struct sender_status *ss, if (ret < 0) goto out; } - sc->header_sent = 1; } + sc->header_sent = 1; ret = send_queued_chunks(sc->fd, sc->cq, max_bytes_per_write); if (ret < 0) { shutdown_client(sc, ss); diff --git a/server.c b/server.c index 2e5f5f74..95ff25cf 100644 --- a/server.c +++ b/server.c @@ -470,18 +470,20 @@ err: static int init_afs(void) { int ret, afs_server_socket[2]; + pid_t afs_pid; ret = socketpair(PF_UNIX, SOCK_DGRAM, 0, afs_server_socket); if (ret < 0) exit(EXIT_FAILURE); afs_socket_cookie = para_random((uint32_t)-1); - mmd->afs_pid = fork(); - if (mmd->afs_pid < 0) + afs_pid = fork(); + if (afs_pid < 0) exit(EXIT_FAILURE); - if (!mmd->afs_pid) { /* child (afs) */ + if (afs_pid == 0) { /* child (afs) */ close(afs_server_socket[0]); afs_init(afs_socket_cookie, afs_server_socket[1]); } + mmd->afs_pid = afs_pid; close(afs_server_socket[1]); ret = mark_fd_nonblocking(afs_server_socket[0]); if (ret < 0) diff --git a/udp_send.c b/udp_send.c index 7217c960..7d13f148 100644 --- a/udp_send.c +++ b/udp_send.c @@ -179,9 +179,7 @@ static int udp_init_session(struct udp_target *ut) } add_close_on_fork_list(ut->fd); ut->cq = cq_new(UDP_CQ_BYTES); - PARA_NOTICE_LOG("sending to udp %s#%d using fec parms %d:%d:%d\n", - ut->host, ut->port , ut->fcp.max_slice_bytes, - ut->fcp.data_slices_per_group, ut->fcp.slices_per_group); + PARA_NOTICE_LOG("sending to udp %s#%d\n", ut->host, ut->port); return 1; } diff --git a/user_list.c b/user_list.c index 63bfdfc2..f5aabc09 100644 --- a/user_list.c +++ b/user_list.c @@ -39,7 +39,7 @@ static void populate_user_list(char *user_list_file) struct user *u; RSA *rsa; - ret = para_fgets(line, MAXLINE, file_ptr); + ret = para_fgets(line, sizeof(line), file_ptr); if (ret <= 0) break; if (sscanf(line,"%200s %200s %200s %200s", w, n, k, p) < 3) diff --git a/versions/paraslash-0.3.6.tar.bz2 b/versions/paraslash-0.3.6.tar.bz2 new file mode 100644 index 00000000..3433a012 Binary files /dev/null and b/versions/paraslash-0.3.6.tar.bz2 differ diff --git a/versions/paraslash-0.3.6.tar.bz2.asc b/versions/paraslash-0.3.6.tar.bz2.asc new file mode 100644 index 00000000..cb571bbc --- /dev/null +++ b/versions/paraslash-0.3.6.tar.bz2.asc @@ -0,0 +1,7 @@ +-----BEGIN PGP SIGNATURE----- +Version: GnuPG v1.4.6 (GNU/Linux) + +iD8DBQBLHTO5Wto1QDEAkw8RAtzpAKCMU4BmDjwy+GBXUVDTCKkh9nTX3wCfe/2N +8tyHsmUOB6MVi2CzFzEdzmE= +=SUFL +-----END PGP SIGNATURE----- diff --git a/vss.c b/vss.c index aae601d1..c6e40533 100644 --- a/vss.c +++ b/vss.c @@ -121,6 +121,8 @@ struct fec_group { uint32_t num_chunks; /** When the first chunk was sent. */ struct timeval start; + /** The duration of the full group. */ + struct timeval duration; /** The group duration divided by the number of slices. */ struct timeval slice_duration; /** Group contains the audio file header that occupies that many slices. */ @@ -232,15 +234,16 @@ static int num_slices(long unsigned bytes, struct fec_client *fc, uint8_t *resul return 1; } -static void set_slice_duration(struct fec_client *fc, struct fec_group *g) +/* set group start and group duration */ +static void set_group_timing(struct fec_client *fc, struct fec_group *g) { - struct timeval group_duration, *chunk_tv = vss_chunk_time(); + struct timeval *chunk_tv = vss_chunk_time(); - tv_scale(g->num_chunks, chunk_tv, &group_duration); + tv_scale(g->num_chunks, chunk_tv, &g->duration); tv_divide(fc->fcp->slices_per_group + fc->num_extra_slices, - &group_duration, &g->slice_duration); + &g->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)); + tv2ms(&g->duration), tv2ms(chunk_tv), tv2ms(&g->slice_duration)); } static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) @@ -248,46 +251,51 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) int ret, i, k, data_slices; size_t len; const char *buf, *start_buf; - struct timeval tmp, *chunk_tv = vss_chunk_time(); struct fec_group *g = &fc->group; unsigned slice_bytes = fc->fcp->max_slice_bytes - FEC_HEADER_SIZE; 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; + g->start = *now; } else { - /* use duration of the previous group for the timing of this group */ - set_slice_duration(fc, g); + /* + * Start and duration of this group depend only on the previous + * group. Compute the new group start as g->start += g->duration. + */ + struct timeval tmp = g->start; + tv_add(&tmp, &g->duration, &g->start); + k = fc->fcp->data_slices_per_group + fc->num_extra_slices; + set_group_timing(fc, g); g->first_chunk += g->num_chunks; g->num++; } @@ -315,7 +323,7 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) assert(g->num_chunks); fc->current_slice_num = 0; if (g->num == 0) - set_slice_duration(fc, g); + set_group_timing(fc, g); /* setup header slices */ buf = vsst->header_buf; @@ -353,14 +361,6 @@ static int setup_next_fec_group(struct fec_client *fc, struct vss_task *vsst) g->first_chunk + g->num_chunks - 1, g->num_header_slices, data_slices ); - /* 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; } diff --git a/web/index.in.html b/web/index.in.html index 8460f841..65b7f0ed 100644 --- a/web/index.in.html +++ b/web/index.in.html @@ -1,6 +1,10 @@

Events


    +
  • 2009-12-07: paraslash-0.3.6 + (sig) + "cubic continuity" +
  • 2009-09-21: paraslash-0.3.5 (sig) "symplectic separability" diff --git a/write.h b/write.h index 1f316fc0..8816be73 100644 --- a/write.h +++ b/write.h @@ -107,6 +107,8 @@ struct writer_node_group { struct task task; /** Whether the group is open, i.e. wng_open() was called. */ int open; + /** Max number of bytes written in the previous post_select() call. */ + int last_written; }; /** Loop over each writer node in a writer group. */ diff --git a/write_common.c b/write_common.c index 476df8f0..2dca309c 100644 --- a/write_common.c +++ b/write_common.c @@ -20,7 +20,7 @@ const char *writer_names[] ={WRITER_NAMES}; /** the array of supported writers */ struct writer writers[NUM_SUPPORTED_WRITERS] = {WRITER_ARRAY}; -static void wng_pre_select(__a_unused struct sched *s, struct task *t) +static void wng_pre_select(struct sched *s, struct task *t) { struct writer_node_group *g = container_of(t, struct writer_node_group, task); int i; @@ -34,13 +34,25 @@ static void wng_pre_select(__a_unused struct sched *s, struct task *t) if (t->error < 0) return; } + /* + * Force a minimal delay if something was written during the previous + * call to wng_post_select(). This is necessary because the filter + * chain might still have data for us which it couldn't convert during + * the previous run due to its buffer size constraints. In this case we + * do not want to wait until the next input data arrives as this could + * lead to buffer underruns. + */ + if (g->last_written == 0) + return; + s->timeout.tv_sec = 0; + s->timeout.tv_usec = 1; } static void wng_post_select(struct sched *s, struct task *t) { struct writer_node_group *g = container_of(t, struct writer_node_group, task); int i; - size_t min_written = 0; + size_t min_written = 0, max_written = 0; FOR_EACH_WRITER_NODE(i, g) { struct writer_node *wn = &g->writer_nodes[i]; @@ -52,7 +64,9 @@ static void wng_post_select(struct sched *s, struct task *t) min_written = wn->written; else min_written = PARA_MIN(min_written, wn->written); + max_written = PARA_MAX(max_written, wn->written); } + g->last_written = max_written; //PARA_INFO_LOG("loaded: %zd, min_written: %zd bytes\n", *g->loaded, min_written); if (min_written) { *g->loaded -= min_written;