From 234647bb5139513bdf36c1afec46f5c43ba27adc Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Fri, 23 Dec 2016 17:18:21 +0100 Subject: [PATCH] server: Store max chunk size in database. This number is needed up-front for the initialization of the fec data structures. Currently we recompute it from the chunk table each time the file is opened for streaming. We can only get rid of the chunk table concept if we tell the VSS by other means how to obtain this information. Fortunately there is an unused 4-byte field in the on-disk afhi structure, which is always zero at the moment. This patch starts to use this field to store the maximal chunk size. For backwards compatibility, when the afhi structure is loaded from disk at stream time, we check if the field is zero and recompute the max chunk size as before in this case. Although the maximal chunk size is generally only needed on the server side, for consistence we expose it though a new status item along with chunk_tv and friends. --- aac_afh.c | 1 + afh.h | 8 +++++++- afh_common.c | 33 +++++++++++++++++++++++++++++++++ aft.c | 39 +++++++++++++++++---------------------- configure.ac | 2 +- flac_afh.c | 1 + mp3_afh.c | 1 + ogg_afh_common.c | 1 + wma_afh.c | 1 + 9 files changed, 63 insertions(+), 24 deletions(-) diff --git a/aac_afh.c b/aac_afh.c index 12ce82df..97b0f474 100644 --- a/aac_afh.c +++ b/aac_afh.c @@ -240,6 +240,7 @@ static int aac_get_file_info(char *map, size_t numbytes, __a_unused int fd, afhi->chunk_table[0] = ret; for (i = 1; i<= afhi->chunks_total; i++) afhi->chunk_table[i] += ret; + set_max_chunk_size(afhi); afhi->channels = channels; afhi->frequency = rate; ret = (afhi->chunk_table[afhi->chunks_total] - afhi->chunk_table[0]) * 8; /* bits */ diff --git a/afh.h b/afh.h index 801c168c..16c01be3 100644 --- a/afh.h +++ b/afh.h @@ -40,6 +40,8 @@ struct afh_info { * the current audio file. */ uint32_t *chunk_table; + /** Size of the largest chunk, introduced in v0.6.0. */ + uint32_t max_chunk_size; /** Period of time between sending data chunks. */ struct timeval chunk_tv; /** @@ -64,7 +66,10 @@ struct audio_file_data { int fd; /** Vss needs this for streaming. */ struct afh_info afhi; - /** Size of the largest chunk. */ + /** + * Size of the largest chunk. Superseded by afhi->max_chunk_size. May + * be removed after v0.6.1. + */ uint32_t max_chunk_size; /** Needed to get the audio file header. */ uint8_t audio_format_id; @@ -130,3 +135,4 @@ void clear_afhi(struct afh_info *afhi); unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **result); int afh_rewrite_tags(int audio_format_id, void *map, size_t mapsize, struct taginfo *tags, int output_fd, const char *filename); +void set_max_chunk_size(struct afh_info *afhi); diff --git a/afh_common.c b/afh_common.c index dfbf7513..75d8b511 100644 --- a/afh_common.c +++ b/afh_common.c @@ -374,6 +374,7 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re "%s: %" PRIu32 "\n" /* seconds total */ "%s: %lu: %lu\n" /* chunk time */ "%s: %" PRIu32 "\n" /* num chunks */ + "%s: %" PRIu32 "\n" /* max chunk size */ "%s: %s\n" /* techinfo */ "%s: %s\n" /* artist */ "%s: %s\n" /* title */ @@ -388,6 +389,7 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re status_item_list[SI_CHUNK_TIME], (long unsigned)afhi->chunk_tv.tv_sec, (long unsigned)afhi->chunk_tv.tv_usec, status_item_list[SI_NUM_CHUNKS], afhi->chunks_total, + status_item_list[SI_MAX_CHUNK_SIZE], afhi->max_chunk_size, status_item_list[SI_TECHINFO], afhi->techinfo? afhi->techinfo : "", status_item_list[SI_ARTIST], afhi->tags.artist? afhi->tags.artist : "", status_item_list[SI_TITLE], afhi->tags.title? afhi->tags.title : "", @@ -397,6 +399,37 @@ unsigned afh_get_afhi_txt(int audio_format_num, struct afh_info *afhi, char **re ); } +/** + * Determine the maximal chunk size by investigating the chunk table. + * + * \param afhi Value/result. + * + * This function iterates over the chunk table and sets ->max_chunk_size + * accordingly. The function exists only for backward compatibility since as of + * version 0.6.0, para_server stores the maximal chunk size in its database. + * This function is only called if the database value is zero, indicating that + * the file was added by an older server version. + */ +void set_max_chunk_size(struct afh_info *afhi) +{ + uint32_t n, max = 0, old = 0; + + for (n = 0; n <= afhi->chunks_total; n++) { + uint32_t val = afhi->chunk_table[n]; + /* + * If the first chunk is the header, do not consider it for the + * calculation of the largest chunk size. + */ + if (n == 0 || (n == 1 && afhi->header_len > 0)) { + old = val; + continue; + } + max = PARA_MAX(max, val - old); + old = val; + } + afhi->max_chunk_size = max; +} + /** * Create a copy of the given file with altered meta tags. * diff --git a/aft.c b/aft.c index 1756ec04..4e2e1f8d 100644 --- a/aft.c +++ b/aft.c @@ -335,8 +335,8 @@ enum afhi_offsets { CHUNKS_TOTAL_OFFSET = 20, /** The length of the audio file header (4 bytes). */ HEADER_LEN_OFFSET = 24, - /** Was: The start of the audio file header (4 bytes). */ - AFHI_UNUSED2_OFFSET = 28, + /** Size of the largest chunk in bytes. (4 bytes). */ + AFHI_MAX_CHUNK_SIZE_OFFSET = 28, /** The seconds part of the chunk time (4 bytes). */ CHUNK_TV_TV_SEC_OFFSET = 32, /** The microseconds part of the chunk time (4 bytes). */ @@ -376,7 +376,7 @@ static void save_afhi(struct afh_info *afhi, char *buf) write_u8(buf + AFHI_CHANNELS_OFFSET, afhi->channels); write_u32(buf + CHUNKS_TOTAL_OFFSET, afhi->chunks_total); write_u32(buf + HEADER_LEN_OFFSET, afhi->header_len); - write_u32(buf + AFHI_UNUSED2_OFFSET, 0); + write_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET, afhi->max_chunk_size); write_u32(buf + CHUNK_TV_TV_SEC_OFFSET, afhi->chunk_tv.tv_sec); write_u32(buf + CHUNK_TV_TV_USEC_OFFSET, afhi->chunk_tv.tv_usec); p = buf + AFHI_INFO_STRING_OFFSET; @@ -398,6 +398,7 @@ static void load_afhi(const char *buf, struct afh_info *afhi) afhi->channels = read_u8(buf + AFHI_CHANNELS_OFFSET); afhi->chunks_total = read_u32(buf + CHUNKS_TOTAL_OFFSET); afhi->header_len = read_u32(buf + HEADER_LEN_OFFSET); + afhi->max_chunk_size = read_u32(buf + AFHI_MAX_CHUNK_SIZE_OFFSET); afhi->chunk_tv.tv_sec = read_u32(buf + CHUNK_TV_TV_SEC_OFFSET); afhi->chunk_tv.tv_usec = read_u32(buf + CHUNK_TV_TV_USEC_OFFSET); afhi->techinfo = (char *)buf + AFHI_INFO_STRING_OFFSET; @@ -415,26 +416,12 @@ static unsigned sizeof_chunk_table(struct afh_info *afhi) return 4 * (afhi->chunks_total + 1); } -static uint32_t save_chunk_table(struct afh_info *afhi, char *buf) +static void save_chunk_table(struct afh_info *afhi, char *buf) { - int i; - uint32_t max = 0, old = 0; + uint32_t n; - for (i = 0; i <= afhi->chunks_total; i++) { - uint32_t val = afhi->chunk_table[i]; - write_u32(buf + 4 * i, val); - /* - * If the first chunk is the header, do not consider it for the - * calculation of the largest chunk size. - */ - if (i == 0 || (i == 1 && afhi->header_len > 0)) { - old = val; - continue; - } - max = PARA_MAX(max, val - old); - old = val; - } - return max; + for (n = 0; n <= afhi->chunks_total; n++) + write_u32(buf + 4 * n, afhi->chunk_table[n]); } static void load_chunk_table(struct afh_info *afhi, const struct osl_object *ct) @@ -638,7 +625,13 @@ static int save_afd(struct audio_file_data *afd) goto err; buf = shm_afd; buf += sizeof(*afd); - afd->max_chunk_size = save_chunk_table(&afd->afhi, buf); + save_chunk_table(&afd->afhi, buf); + if (afd->afhi.max_chunk_size == 0) { /* v0.5.x on-disk afhi */ + set_max_chunk_size(&afd->afhi); + PARA_NOTICE_LOG("max chunk size unset, re-add required\n"); + } else + PARA_INFO_LOG("using max chunk size from afhi\n"); + afd->max_chunk_size = afd->afhi.max_chunk_size; *(struct audio_file_data *)shm_afd = *afd; shm_detach(shm_afd); return shmid; @@ -947,6 +940,8 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, WRITE_STATUS_ITEM(b, SI_CHUNK_TIME, "%lu\n", tv2ms(&afhi->chunk_tv)); WRITE_STATUS_ITEM(b, SI_NUM_CHUNKS, "%" PRIu32 "\n", afhi->chunks_total); + WRITE_STATUS_ITEM(b, SI_MAX_CHUNK_SIZE, "%" PRIu32 "\n", + afhi->max_chunk_size); WRITE_STATUS_ITEM(b, SI_TECHINFO, "%s\n", afhi->techinfo); WRITE_STATUS_ITEM(b, SI_ARTIST, "%s\n", afhi->tags.artist); WRITE_STATUS_ITEM(b, SI_TITLE, "%s\n", afhi->tags.title); diff --git a/configure.ac b/configure.ac index 0b00cc2a..fe6d70c4 100644 --- a/configure.ac +++ b/configure.ac @@ -1022,7 +1022,7 @@ attributes_txt decoder_flags audiod_status play_time attributes_bitmap offset seconds_total stream_start current_time audiod_uptime image_id lyrics_id duration directory lyrics_name image_name path hash channels last_played num_chunks chunk_time amplification artist title year album -comment" +comment max_chunk_size" result= for i in $status_items; do diff --git a/flac_afh.c b/flac_afh.c index 385d4f0c..e2d53802 100644 --- a/flac_afh.c +++ b/flac_afh.c @@ -391,6 +391,7 @@ static int flac_afh_read_chunks(struct private_flac_afh_data *pfad) break; } afhi->chunks_total = c; + set_max_chunk_size(afhi); ret = 1; free_decoder: FLAC__stream_decoder_finish(decoder); diff --git a/mp3_afh.c b/mp3_afh.c index 2115f71c..e5d0ff13 100644 --- a/mp3_afh.c +++ b/mp3_afh.c @@ -657,6 +657,7 @@ static int mp3_read_info(unsigned char *map, size_t numbytes, int fd, tv_divide(afhi->chunks_total, &total_time, &afhi->chunk_tv); PARA_DEBUG_LOG("%" PRIu32 "chunks, each %lums\n", afhi->chunks_total, tv2ms(&afhi->chunk_tv)); + set_max_chunk_size(afhi); ret = mp3_get_id3(map, numbytes, fd, &afhi->tags); afhi->techinfo = make_message("%cbr, %s, %s tags", vbr? 'v' : 'c', header_mode(&header), tag_versions[ret]); diff --git a/ogg_afh_common.c b/ogg_afh_common.c index 6e5a8934..734fd586 100644 --- a/ogg_afh_common.c +++ b/ogg_afh_common.c @@ -181,6 +181,7 @@ int ogg_get_file_info(char *map, size_t numbytes, struct afh_info *afhi, } } afhi->chunks_total = j; + set_max_chunk_size(afhi); set_chunk_tv(frames_per_chunk, afhi->frequency, &afhi->chunk_tv); ret = 0; out: diff --git a/wma_afh.c b/wma_afh.c index 4c9d87e0..b4059896 100644 --- a/wma_afh.c +++ b/wma_afh.c @@ -229,6 +229,7 @@ static int wma_make_chunk_table(char *buf, size_t buf_size, uint32_t packet_size } } afhi->chunks_total = j; + set_max_chunk_size(afhi); set_chunk_tv(frames_per_chunk, afhi->frequency, &afhi->chunk_tv); return 1; fail: -- 2.39.2