From 0e8849e41ffaffdc94231568ff0a0a061500e341 Mon Sep 17 00:00:00 2001 From: Andre Noll Date: Mon, 10 Sep 2007 02:05:15 +0200 Subject: [PATCH] afs com_add(): Recognize also audio formats different from mp3. This required adding two more callbacks: path_brother_callback() and hash_sister_callback(). These are called from add_one_audio_file() which runs from handler context and can thus not access the database directly. --- afs.c | 2 +- aft.c | 118 ++++++++++++++++++++++++++++++++++++++------------------ error.h | 12 +++--- vss.c | 70 +++++++++++++++++++++++++-------- vss.h | 4 +- 5 files changed, 142 insertions(+), 64 deletions(-) diff --git a/afs.c b/afs.c index 806d0fbd..5e9bd118 100644 --- a/afs.c +++ b/afs.c @@ -674,7 +674,7 @@ static void command_post_select(struct sched *s, struct task *t) goto out; } if (t->ret != sizeof(buf)) { - PARA_NOTICE_LOG("short read (%d bytes, expected %lu)\n", + PARA_NOTICE_LOG("short read (%d bytes, expected %u)\n", t->ret, sizeof(buf)); t->ret = 1; goto out; diff --git a/aft.c b/aft.c index f1616adf..e1004d00 100644 --- a/aft.c +++ b/aft.c @@ -6,16 +6,14 @@ #include "afs.h" #include "net.h" #include "string.h" - -int mp3_get_file_info(char *map, size_t numbytes, - struct audio_format_info *afi); /* FXIME */ +#include "vss.h" #define AFS_AUDIO_FILE_DIR "/home/mp3" -static void *audio_file_table; +static struct osl_table *audio_file_table; /** - * Describes the structure of the mmapped-afs info struct. + * Describes the layout of the mmapped-afs info struct. * * \sa struct afs_info. */ @@ -46,19 +44,8 @@ enum afsi_offsets { */ void save_afsi(struct afs_info *afsi, struct osl_object *obj) { - struct afs_info default_afs_info = { - .last_played = time(NULL) - 365 * 24 * 60 * 60, - .attributes = 0, - .num_played = 0, - .image_id = 0, - .lyrics_id = 0, - .audio_format_id = 5, /* FIXME */ - }; char *buf = obj->data; - if (!afsi) - afsi = &default_afs_info; - write_u64(buf + AFSI_LAST_PLAYED_OFFSET, afsi->last_played); write_u64(buf + AFSI_ATTRIBUTES_OFFSET, afsi->attributes); write_u32(buf + AFSI_NUM_PLAYED_OFFSET, afsi->num_played); @@ -366,6 +353,8 @@ static int load_chunk_info(struct osl_object *obj, struct audio_format_info *afh int aft_get_row_of_path(char *path, struct osl_row **row) { struct osl_object obj = {.data = path, .size = strlen(path) + 1}; + + PARA_NOTICE_LOG("audio_file_table: %p\n", audio_file_table); return osl_get_row(audio_file_table, AFTCOL_PATH, &obj, row); } @@ -715,7 +704,7 @@ static int print_list_item(struct ls_data *d, struct ls_options *opts, w->image_id_width, afsi->image_id, w->lyrics_id_width, afsi->lyrics_id, w->bitrate_width, afhi->bitrate, - "mp3", /* FIXME */ + audio_format_name(afsi->audio_format_id), /* FIXME */ w->frequency_width, afhi->frequency, afhi->channels, duration_buf, @@ -1156,7 +1145,7 @@ int audio_file_loop(void *private_data, osl_rbtree_loop_func *func) func); } -static void *find_hash_sister(HASH_TYPE *hash) +static struct osl_row *find_hash_sister(HASH_TYPE *hash) { const struct osl_object obj = {.data = hash, .size = HASH_SIZE}; struct osl_row *row; @@ -1165,21 +1154,20 @@ static void *find_hash_sister(HASH_TYPE *hash) return row; } -#define AFTROW_HEADER_SIZE 4 - enum aft_row_offsets { AFTROW_AFHI_OFFSET_POS = 0, AFTROW_CHUNKS_OFFSET_POS = 2, - AFTROW_HASH_OFFSET = AFTROW_HEADER_SIZE, - AFTROW_FLAGS_OFFSET = (AFTROW_HASH_OFFSET + HASH_SIZE), - AFTROW_PATH_OFFSET = (AFTROW_FLAGS_OFFSET + 4) + AFTROW_AUDIO_FORMAT_OFFSET = 4, + AFTROW_FLAGS_OFFSET = 5, + AFTROW_HASH_OFFSET = 9, + AFTROW_PATH_OFFSET = (AFTROW_HASH_OFFSET + HASH_SIZE), }; /* never save the afsi, as the server knows it too. Note that afhi might be NULL. * In this case, afhi won't be stored in the buffer */ static void save_audio_file_info(HASH_TYPE *hash, const char *path, - struct audio_format_info *afhi, - uint32_t flags, struct osl_object *obj) + struct audio_format_info *afhi, uint32_t flags, + uint8_t audio_format_num, struct osl_object *obj) { size_t path_len = strlen(path) + 1; size_t afhi_size = sizeof_afhi_buf(afhi); @@ -1188,8 +1176,10 @@ static void save_audio_file_info(HASH_TYPE *hash, const char *path, char *buf = para_malloc(size); uint16_t pos; - memcpy(buf + AFTROW_HASH_OFFSET, hash, HASH_SIZE); + write_u8(buf + AFTROW_AUDIO_FORMAT_OFFSET, audio_format_num); write_u32(buf + AFTROW_FLAGS_OFFSET, flags); + + memcpy(buf + AFTROW_HASH_OFFSET, hash, HASH_SIZE); strcpy(buf + AFTROW_PATH_OFFSET, path); pos = AFTROW_PATH_OFFSET + path_len; @@ -1266,6 +1256,7 @@ static int com_add_callback(const struct osl_object *query, int ret; char afsi_buf[AFSI_SIZE]; uint32_t flags = read_u32(buf + AFTROW_FLAGS_OFFSET); + struct afs_info default_afsi = {.last_played = 0}; hash = (HASH_TYPE *)buf + AFTROW_HASH_OFFSET; hash_to_asc(hash, asc);; @@ -1353,11 +1344,14 @@ static int com_add_callback(const struct osl_object *query, return ret; } /* new entry, use default afsi */ + default_afsi.last_played = time(NULL) - 365 * 24 * 60 * 60; + default_afsi.audio_format_id = read_u8(buf + AFTROW_AUDIO_FORMAT_OFFSET); + if (flags & ADD_FLAG_VERBOSE) PARA_NOTICE_LOG("adding %s\n", path); objs[AFTCOL_AFSI].data = &afsi_buf; objs[AFTCOL_AFSI].size = AFSI_SIZE; - save_afsi(NULL, &objs[AFTCOL_AFSI]); + save_afsi(&default_afsi, &objs[AFTCOL_AFSI]); ret = osl_add_and_get_row(audio_file_table, objs, &aft_row); if (ret < 0) return ret; @@ -1369,13 +1363,44 @@ struct private_add_data { uint32_t flags; }; +static int path_brother_callback(const struct osl_object *query, + struct osl_object *result) +{ + char *path = query->data; + struct osl_row *path_brother; + int ret = aft_get_row_of_path(path, &path_brother); + if (ret < 0) + return ret; + result->data = para_malloc(sizeof(path_brother)); + result->size = sizeof(path_brother); + *(struct osl_row **)(result->data) = path_brother; + return 1; +} + +static int hash_sister_callback(const struct osl_object *query, + struct osl_object *result) +{ + HASH_TYPE *hash = query->data; + struct osl_row *hash_sister; + + hash_sister = find_hash_sister(hash); + if (!hash_sister) + return -E_RB_KEY_NOT_FOUND; + result->data = para_malloc(sizeof(hash_sister)); + result->size = sizeof(hash_sister); + *(struct osl_row **)(result->data) = hash_sister; + return 1; +} + + static int add_one_audio_file(const char *arg, const void *private_data) { int ret; + uint8_t format_num = -1; const struct private_add_data *pad = private_data; struct audio_format_info afhi, *afhi_ptr = NULL; - struct osl_row *pb, *hs; /* path brother/hash sister */ - struct osl_object map, obj = {.data = NULL}; + struct osl_row *pb = NULL, *hs = NULL; /* path brother/hash sister */ + struct osl_object map, obj, query, result; char *path; HASH_TYPE hash[HASH_SIZE]; @@ -1384,24 +1409,38 @@ static int add_one_audio_file(const char *arg, const void *private_data) ret = verify_path(arg, &path); if (ret < 0) return ret; - ret = aft_get_row_of_path(path, &pb); + query.data = path; + query.size = strlen(path) + 1; + ret = send_callback_request(path_brother_callback, &query, &result); if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND) goto out_free; + if (ret >= 0) { + pb = *(struct osl_row **)result.data; + free(result.data); + } ret = 1; if (pb && (pad->flags & ADD_FLAG_LAZY)) { /* lazy is really cheap */ if (pad->flags & ADD_FLAG_VERBOSE) PARA_NOTICE_LOG("lazy-ignore: %s\n", path); goto out_free; } - /* we still want to add this file. Compute its hash and look it up */ + /* We still want to add this file. Compute its hash. */ ret = mmap_full_file(path, O_RDONLY, &map); if (ret < 0) goto out_free; hash_function(map.data, map.size, hash); - hs = find_hash_sister(hash); - /* - * return success if we're pretty sure that we already know this file - */ + + /* Check whether database contains file with the same hash. */ + query.data = hash; + query.size = HASH_SIZE; + ret = send_callback_request(hash_sister_callback, &query, &result); + if (ret < 0 && ret != -E_RB_KEY_NOT_FOUND) + goto out_free; + if (ret >= 0) { + hs = *(struct osl_row **)result.data; + free(result.data); + } + /* Return success if we already know this file. */ ret = 1; if (pb && hs && hs == pb && (!(pad->flags & ADD_FLAG_FORCE))) { if (pad->flags & ADD_FLAG_VERBOSE) @@ -1413,17 +1452,18 @@ static int add_one_audio_file(const char *arg, const void *private_data) * there is a hash sister unless in FORCE mode. */ if (!hs || (pad->flags & ADD_FLAG_FORCE)) { - ret = mp3_get_file_info(map.data, map.size, &afhi); + ret = compute_afhi(path, map.data, map.size, &afhi); if (ret < 0) { PARA_WARNING_LOG("audio format of %s not recognized, skipping\n", path); ret = 1; goto out_unmap; } + format_num = ret; afhi_ptr = &afhi; } munmap(map.data, map.size); - save_audio_file_info(hash, path, afhi_ptr, pad->flags, &obj); - /* ask parent to consider this entry for adding */ + save_audio_file_info(hash, path, afhi_ptr, pad->flags, format_num, &obj); + /* Ask afs to consider this entry for adding. */ ret = send_callback_request(com_add_callback, &obj, NULL); goto out_free; @@ -1443,6 +1483,7 @@ int com_add(int fd, int argc, char * const * const argv) struct private_add_data pad = {.fd = fd, .flags = 0}; struct stat statbuf; + PARA_NOTICE_LOG("argv[1]: %s\n", argv[1]); for (i = 1; i < argc; i++) { const char *arg = argv[i]; if (arg[0] != '-') @@ -1687,6 +1728,7 @@ int aft_init(struct table_info *ti) PARA_INFO_LOG("audio file table contains %d files\n", num); return ret; } + PARA_INFO_LOG("failed to open audio file table\n"); audio_file_table = NULL; return ret == -E_NOENT? 1 : ret; } diff --git a/error.h b/error.h index 8c113912..9bc8ed52 100644 --- a/error.h +++ b/error.h @@ -122,11 +122,11 @@ extern const char **para_errlist[]; PARA_ERROR(NOTDIR, "fixme"), \ PARA_ERROR(NOENT, "fixme"), \ PARA_ERROR(OSL_PERM, "fixme"), \ - PARA_ERROR(BAD_TABLE, "fixme"), \ - PARA_ERROR(BAD_TABLE_HEADER, "fixme"), \ + PARA_ERROR(BAD_TABLE, "table not open"), \ + PARA_ERROR(BAD_TABLE_HEADER, "table header corruption"), \ PARA_ERROR(BAD_TABLE_DESC, "fixme"), \ - PARA_ERROR(RB_KEY_EXISTS, "fixme"), \ - PARA_ERROR(RB_KEY_NOT_FOUND, "fixme"), \ + PARA_ERROR(RB_KEY_EXISTS, "key already exists in rbtree"), \ + PARA_ERROR(RB_KEY_NOT_FOUND, "key not found in rbtree"), \ PARA_ERROR(BAD_ID, "fixme"), \ PARA_ERROR(INDEX_CORRUPTION, "fixme"), \ PARA_ERROR(BAD_OFFSET, "fixme"), \ @@ -202,8 +202,8 @@ extern const char **para_errlist[]; PARA_ERROR(FNMATCH, "fixme"), \ PARA_ERROR(NO_MATCH, "fixme"), \ PARA_ERROR(NO_AFHI, "fixme"), \ - PARA_ERROR(AFT_SYNTAX, "fixme"), \ - PARA_ERROR(AFS_STAT, "fixme"), \ + PARA_ERROR(AFT_SYNTAX, "syntax error"), \ + PARA_ERROR(AFS_STAT, "stat(2) failed"), \ PARA_ERROR(HASH_MISMATCH, "fixme"), \ diff --git a/vss.c b/vss.c index e0c0b584..3ef850c7 100644 --- a/vss.c +++ b/vss.c @@ -38,9 +38,8 @@ extern struct sender senders[]; static int audio_file; static char *map; -#if 1 - void mp3_init(struct audio_format_handler *); -#endif +/* The mp3 audio format handler does not need any libs. */ +void mp3_init(struct audio_format_handler *); #ifdef HAVE_OGGVORBIS void ogg_init(struct audio_format_handler *); @@ -50,35 +49,53 @@ static char *map; #endif /** - * the list of supported audio formats + * The list of supported audio formats. + * + * We always define the full array of audio formats even if some audio formats + * were not compiled in. This is because for each audio file the number of its + * audio format is stored in the databse. We don't want that numbers to become + * stale just because the user installed a new version of paraslash that + * supports a different set of audio formats. + * + * It can still be easily detected whether an audio format is compiled in by + * checking if the init function pointer is not \p NULL. */ static struct audio_format_handler afl[] = { -#if 1 { .name = "mp3", .init = mp3_init, }, -#endif -#ifdef HAVE_OGGVORBIS { .name = "ogg", +#ifdef HAVE_OGGVORBIS .init = ogg_init, - }, #endif -#ifdef HAVE_FAAD + }, { .name = "aac", +#ifdef HAVE_FAAD .init = aac_afh_init, - }, #endif + }, { .name = NULL, } }; -/** iterate over each supported audio format */ -#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i++) +static inline int next_audio_format(int format) +{ + for (;;) { + if (!afl[format].name) + return format; + format++; + if (afl[format].init) + return format; + } + +} +/** Iterate over each supported audio format. */ +#define FOR_EACH_AUDIO_FORMAT(i) for (i = 0; afl[i].name; i = next_audio_format(i)) /** @@ -128,6 +145,7 @@ unsigned int vss_paused(void) /** * get the name of the given audio format + * * \param i the audio format number * * This returns a pointer to statically allocated memory so it @@ -226,24 +244,42 @@ static int get_audio_format(int omit) return -E_AUDIO_FORMAT; } -int get_audio_file_info(const char *path, char *data, size_t size, +/** + * Call get_file_info() to obtain an afhi structure. + * + * \param path The full path of the audio file. + * \param data Pointer to the contents of the (mapped) file. + * \param size The file size in bytes. + * \param afhi Result pointer. + * + * \return The number of the audio format on success, \p -E_AUDIO_FORMAT if no + * compiled in audio format handler is able to handler the file. + * + * This function tries to find an audio format handler that can interpret the + * file given by \a data and \a size. + * + * It first tries to determine the audio format from the filename given by \a + * path. If this doesn't work, all other audio format handlers are tried until + * one is found that can handle the file. + */ +int compute_afhi(const char *path, char *data, size_t size, struct audio_format_info *afhi) { int ret, i, format = guess_audio_format(path); + if (format >= 0) { ret = afl[format].get_file_info(data, size, afhi); if (ret >= 0) - return ret; + return format; } FOR_EACH_AUDIO_FORMAT(i) { if (i == format) /* we already tried this one to no avail */ continue; ret = afl[i].get_file_info(data, size, afhi); if (ret >= 0) - return ret; + return i; } return -E_AUDIO_FORMAT; - } /* @@ -413,7 +449,7 @@ static void vss_eof(void) } /** - * get the header and of the current audio file + * Get the header of the current audio file. * * \param header_len the length of the header is stored here * diff --git a/vss.h b/vss.h index 3374e946..9b10a5e8 100644 --- a/vss.h +++ b/vss.h @@ -16,8 +16,8 @@ unsigned int vss_paused(void); char *vss_get_header(size_t *header_len); struct timeval *vss_chunk_time(void); int guess_audio_format(const char *name); -int get_audio_file_info(const char *path, char *data, size_t size, - struct audio_format_info *afhi); +int compute_afhi(const char *path, char *data, size_t size, + struct audio_format_info *afhi); const char *supported_audio_formats(void); int vss_get_chunk(long unsigned chunk_num, char **buf, size_t *len); -- 2.39.2