From: Andre Noll Date: Sun, 3 Oct 2010 11:07:42 +0000 (+0200) Subject: Add Infrastructure for dynamic header computation. X-Git-Tag: v0.4.6~19^2~6 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=0e3764a52eb6af123414ce07bcceb2c8bd2836c1 Add Infrastructure for dynamic header computation. vorbis allows to add arbitrary many comments to an audio file. These comments are stored in ogg packet #2, which is part of the audio file header of ogg vorbis files. Hence ogg/vorbis headers may be arbitrary large. Since the header is sent periodically, this wastes bandwidth and may cause FEC parameters to become unnecessary large. This introductory patch paves the way for replacing ogg packet #2 at stream time by a dummy packet with does not contain any comments and is therefore of bounded size. In order to do so, we need audio file headers which are not necessarily an unmodified portion of the audio file. Therefore we call back into the audio format handler code at stream time to compute an appropriate audio file header. Hence an optional new method ->get_header() is added to struct audio_format_hander. If it is non-NULL, is is called instead of using the first header_len bytes of the file. Unfortunately, this implies that the virtual streaming system must be aware of the audio format id in order to know which get_header() method should be called. Thus we store the audio format id in struct audio_file_data which is passed from the afs process to the server process. Vss then calls afh_get_header() with the audio format id as an additional argument. ATM, the new functionality is not yet used as as no audio format handler defines ->get_header() yet. --- diff --git a/afh.c b/afh.c index b5fb65fc..c5d7aec2 100644 --- a/afh.c +++ b/afh.c @@ -83,15 +83,16 @@ static void print_chunk_table(struct afh_info *afhi) } } -static int cat_file(void *audio_file_data, struct afh_info *afhi) +static int cat_file(struct afh_info *afhi, int audio_format_id, + void *audio_file_data, size_t audio_file_size) { int ret; struct timeval stream_start; long unsigned i, first_chunk, last_chunk; const char *buf; + char *header; size_t size; - if (conf.begin_chunk_arg < 0) { if (-conf.begin_chunk_arg > afhi->chunks_total) return -ERRNO_TO_PARA_ERROR(EINVAL); @@ -114,14 +115,18 @@ static int cat_file(void *audio_file_data, struct afh_info *afhi) return -ERRNO_TO_PARA_ERROR(EINVAL); if (!afhi->chunks_total) return 1; - afh_get_header(afhi, audio_file_data, &buf, &size); - if (size && first_chunk && !conf.no_header_given) { - PARA_INFO_LOG("writing audio file header (%zu bytes)\n", size); - ret = write(STDOUT_FILENO, buf, size); - if (ret < 0) - return ret; - if (ret != size) - return -E_AFH_SHORT_WRITE; + if (first_chunk > 0 && !conf.no_header_given) { + afh_get_header(afhi, audio_format_id, audio_file_data, audio_file_size, + &header, &size); + if (size > 0) { + PARA_INFO_LOG("writing header (%zu bytes)\n", size); + ret = write(STDOUT_FILENO, header, size); /* FIXME */ + afh_free_header(header, audio_format_id); + if (ret < 0) + return ret; + if (ret != size) + return -E_AFH_SHORT_WRITE; + } } PARA_NOTICE_LOG("writing chunks %lu - %lu\n", first_chunk, last_chunk); gettimeofday(&stream_start, NULL); @@ -184,9 +189,11 @@ int main(int argc, char **argv) fd, &afhi); if (ret < 0) goto out; + audio_format_num = ret; if (conf.stream_given) - ret = cat_file(audio_file_data, &afhi); + ret = cat_file(&afhi, audio_format_num, + audio_file_data, audio_file_size); else { printf("File %d: %s\n", i + 1, conf.inputs[i]); print_info(audio_format_num, &afhi); diff --git a/afh.h b/afh.h index 494a4e15..8b747f8a 100644 --- a/afh.h +++ b/afh.h @@ -90,6 +90,8 @@ struct audio_format_handler { */ int (*get_file_info)(char *map, size_t numbytes, int fd, struct afh_info *afi); + + void (*get_header)(void *map, size_t mapsize, char **buf, size_t *len); }; void afh_init(void); @@ -99,4 +101,7 @@ int compute_afhi(const char *path, char *data, size_t size, const char *audio_format_name(int); void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi, void *map, const char **buf, size_t *len); -void afh_get_header(struct afh_info *afhi, void *map, const char **buf, size_t *len); +uint32_t afh_get_largest_chunk_size(struct afh_info *afhi); +void afh_get_header(struct afh_info *afhi, uint8_t audio_format_id, + void *map, size_t mapsize, char **buf, size_t *len); +void afh_free_header(char *header_buf, uint8_t audio_format_id); diff --git a/afh_common.c b/afh_common.c index 10376ba6..7ecab4e4 100644 --- a/afh_common.c +++ b/afh_common.c @@ -248,21 +248,52 @@ void afh_get_chunk(long unsigned chunk_num, struct afh_info *afhi, * Get the header of an audio file. * * \param afhi The audio file handler data describing the file. + * \param audio_format_id Determines the audio format handler. * \param map The data of the audio file. + * \param mapsize The amount of bytes of the mmapped audio file. * \param buf The length of the header is stored here. * \param len Points to a buffer containing the header on return. * * This function sets \a buf to \p NULL and \a len to zero if \a map or \a * afhi is \p NULL, or if the current audio format does not need special * header treatment. + * + * Otherwise, it is checked whether the audio format handler given by + * \a audio_format_id defines a ->get_header() method. If it does, this + * method is called to obtain the header. If ->get_header() is \p NULL, + * a reference to the first chunk of the audio file is returned. + * + * Once the header is no longer needed, the caller must call \ref + * afh_free_header() to free the resources allocated by this function. */ -void afh_get_header(struct afh_info *afhi, void *map, const char **buf, size_t *len) +void afh_get_header(struct afh_info *afhi, uint8_t audio_format_id, + void *map, size_t mapsize, char **buf, size_t *len) { + struct audio_format_handler *afh = afl + audio_format_id; + if (!map || !afhi || !afhi->header_len) { *buf = NULL; *len = 0; return; } - *len = afhi->header_len; - *buf = map; + if (!afh->get_header) { + *len = afhi->header_len; + *buf = map; + return; + } + afh->get_header(map, mapsize, buf, len); +} + +/** + * Deallocate any resources obtained from afh_get_header(). + * + * \param header_buf Pointer obtained via afh_get_header(). + * \param audio_format_id Determines the audio format handler. + */ +void afh_free_header(char *header_buf, uint8_t audio_format_id) +{ + struct audio_format_handler *afh = afl + audio_format_id; + + if (afh->get_header) + free(header_buf); } diff --git a/afs.h b/afs.h index cd98a9f8..96da2da0 100644 --- a/afs.h +++ b/afs.h @@ -131,6 +131,8 @@ struct audio_file_data { struct afh_info afhi; /** Size of the largest chunk. */ uint32_t max_chunk_size; + /** Needed to get the audio file header. */ + uint8_t audio_format_id; }; /** diff --git a/aft.c b/aft.c index 9f39d705..266188b5 100644 --- a/aft.c +++ b/aft.c @@ -1124,6 +1124,7 @@ int open_and_update_audio_file(struct osl_row *aft_row, long score, new_afsi.last_played = time(NULL); save_afsi(&new_afsi, &afsi_obj); /* in-place update */ + afd->audio_format_id = old_afsi.audio_format_id; load_chunk_table(&afd->afhi, chunk_table_obj.data); ret = make_status_items(afd, &old_afsi, path, score, file_hash); if (ret < 0) diff --git a/vss.c b/vss.c index 21ac3747..8b374521 100644 --- a/vss.c +++ b/vss.c @@ -86,7 +86,7 @@ struct vss_task { /** 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. */ @@ -807,6 +807,8 @@ static void vss_eof(struct vss_task *vsst) 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; @@ -985,8 +987,8 @@ static void recv_afs_result(struct vss_task *vsst, fd_set *rfds) 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);