From: Andre Noll Date: Sun, 10 Apr 2016 21:46:02 +0000 (+0200) Subject: Merge branch 'refs/heads/t/attribute_fix' X-Git-Tag: v0.5.6~41 X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=commitdiff_plain;h=4ad8a5536d7cea1e63137933b242c52e57bd53d6;hp=7ccb64e6af4763240a262a4158a9ac71ddf597a2 Merge branch 'refs/heads/t/attribute_fix' com_setatt() was broken if more than 32 attributes are defined. The branch merged in this commit contains a fix for this bug, and a new test that exercises the code related to attributes. Was cooking in next for six weeks. * refs/heads/t/attribute_fix: manual: Add realpath to list of packages. Add test that exercises attribute code. test-lib: Canonicalize test_dir. attribute: Avoid shifting 32 bit integers. --- diff --git a/Makefile.real b/Makefile.real index ee0bf447..289e027a 100644 --- a/Makefile.real +++ b/Makefile.real @@ -174,7 +174,8 @@ $(man_dir)/para_server.1: man_util_command_lists := $(server_command_lists) $(man_dir)/para_audiod.1: man_util_command_lists := $(audiod_command_lists) $(man_dir)/para_play.1: man_util_command_lists := $(play_command_lists) -$(man_dir)/para_%.1: $(ggo_dir)/%.ggo man_util.bash | $(man_dir) $(help2man_dir) +$(man_dir)/para_%.1: $(ggo_dir)/%.ggo man_util.bash \ + git-version.h | $(man_dir) $(help2man_dir) @[ -z "$(Q)" ] || echo 'MAN $<' $(Q) \ COMMAND_LISTS="$(man_util_command_lists)" \ diff --git a/NEWS b/NEWS index a5bef9f6..22e2ebc0 100644 --- a/NEWS +++ b/NEWS @@ -5,6 +5,11 @@ NEWS current master branch "cascading gradient" ------------------------------------------ +The highlight of this release is the new -m flag for para_afh which +lets it modify the meta tags of the given audio file(s). This feature +is supported for all audio formats. Many small cleanups and bug fixes +not mentioned here have accumulated and are also part of the release. + - para_afh learned to modify meta tags of mp3 wma ogg spx opus flac aac files. - afs commands propagate error codes to the client. @@ -12,7 +17,9 @@ current master branch "cascading gradient" inconsistencies. - New -v flag for the version command (print verbose version string) - New option --priority for para_server and para_audiod. + - New mood methods: image_id and lyrics_id. +Download: ./releases/paraslash-git.tar.bz2 (tarball) -------------------------------------- 0.5.5 (2015-09-20) "magnetic momentum" diff --git a/afs.c b/afs.c index d5afc6d9..ee1c6b5d 100644 --- a/afs.c +++ b/afs.c @@ -424,7 +424,7 @@ static int pass_afd(int fd, char *buf, size_t size) { struct msghdr msg = {.msg_iov = NULL}; struct cmsghdr *cmsg; - char control[255]; + char control[255] __a_aligned(8); int ret; struct iovec iov; diff --git a/client.c b/client.c index 35b49a16..31cfff09 100644 --- a/client.c +++ b/client.c @@ -204,7 +204,6 @@ I9E_DUMMY_COMPLETER(pause); I9E_DUMMY_COMPLETER(play); I9E_DUMMY_COMPLETER(si); I9E_DUMMY_COMPLETER(term); -I9E_DUMMY_COMPLETER(version); I9E_DUMMY_COMPLETER(stop); I9E_DUMMY_COMPLETER(addatt); I9E_DUMMY_COMPLETER(init); @@ -218,6 +217,13 @@ static void help_completer(struct i9e_completion_info *ci, result->matches = i9e_complete_commands(ci->word, completers); } +static void version_completer(struct i9e_completion_info *ci, + struct i9e_completion_result *cr) +{ + char *opts[] = {"-v", NULL}; + i9e_complete_option(opts, ci, cr); +} + static void stat_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { @@ -317,11 +323,7 @@ static void lsatt_completer(struct i9e_completion_info *ci, struct i9e_completion_result *cr) { char *opts[] = {"-i", "-l", "-r", NULL}; - - if (ci->word[0] == '-') - i9e_complete_option(opts, ci, cr); - else - complete_attributes(ci->word, &cr->matches); + i9e_complete_option(opts, ci, cr); } static void mvatt_completer(struct i9e_completion_info *ci, diff --git a/command.c b/command.c index bde14587..93de2d2d 100644 --- a/command.c +++ b/command.c @@ -161,9 +161,8 @@ static unsigned get_status(struct misc_meta_data *nmmd, int parser_friendly, static int check_sender_args(int argc, char * const * argv, struct sender_command_data *scd) { int i; - /* this has to match sender.h */ - const char *subcmds[] = {"add", "delete", "allow", "deny", "on", "off", NULL}; + const char *subcmds[] = {SENDER_SUBCOMMANDS NULL}; scd->sender_num = -1; if (argc < 3) return -E_COMMAND_SYNTAX; @@ -183,19 +182,19 @@ static int check_sender_args(int argc, char * const * argv, struct sender_comman if (!senders[scd->sender_num].client_cmds[scd->cmd_num]) return -E_SENDER_CMD; switch (scd->cmd_num) { - case SENDER_ON: - case SENDER_OFF: + case SENDER_on: + case SENDER_off: if (argc != 3) return -E_COMMAND_SYNTAX; break; - case SENDER_DENY: - case SENDER_ALLOW: + case SENDER_deny: + case SENDER_allow: if (argc != 4 || parse_cidr(argv[3], scd->host, sizeof(scd->host), &scd->netmask) == NULL) return -E_COMMAND_SYNTAX; break; - case SENDER_ADD: - case SENDER_DELETE: + case SENDER_add: + case SENDER_delete: if (argc != 4) return -E_COMMAND_SYNTAX; return parse_fec_url(argv[3], scd); @@ -358,8 +357,8 @@ static int com_sender(struct command_context *cc) } switch (scd.cmd_num) { - case SENDER_ADD: - case SENDER_DELETE: + case SENDER_add: + case SENDER_delete: assert(senders[scd.sender_num].resolve_target); ret = senders[scd.sender_num].resolve_target(cc->argv[3], &scd); if (ret < 0) diff --git a/dccp_send.c b/dccp_send.c index b038fc01..92dd9333 100644 --- a/dccp_send.c +++ b/dccp_send.c @@ -225,12 +225,12 @@ void dccp_send_init(struct sender *s) s->shutdown_clients = dccp_shutdown_clients; s->resolve_target = NULL; s->help = generic_sender_help; - s->client_cmds[SENDER_ON] = dccp_com_on; - s->client_cmds[SENDER_OFF] = dccp_com_off; - s->client_cmds[SENDER_DENY] = dccp_com_deny; - s->client_cmds[SENDER_ALLOW] = dccp_com_allow; - s->client_cmds[SENDER_ADD] = NULL; - s->client_cmds[SENDER_DELETE] = NULL; + s->client_cmds[SENDER_on] = dccp_com_on; + s->client_cmds[SENDER_off] = dccp_com_off; + s->client_cmds[SENDER_deny] = dccp_com_deny; + s->client_cmds[SENDER_allow] = dccp_com_allow; + s->client_cmds[SENDER_add] = NULL; + s->client_cmds[SENDER_delete] = NULL; k = conf.dccp_data_slices_per_group_arg; n = conf.dccp_slices_per_group_arg; diff --git a/error.h b/error.h index 75532ea2..b7352333 100644 --- a/error.h +++ b/error.h @@ -419,7 +419,6 @@ extern const char **para_errlist[]; PARA_ERROR(MP4ASC, "audio spec config error"), \ PARA_ERROR(AAC_AFH_INIT, "failed to init aac decoder"), \ PARA_ERROR(MP4V2, "mp4v2 library error"), \ - PARA_ERROR(NO_AUDIO_TRACK, "file contains no valid audio track"), \ #define AAC_COMMON_ERRORS \ PARA_ERROR(ESDS, "did not find esds atom"), \ diff --git a/gui.c b/gui.c index 1a89681d..9d96e70f 100644 --- a/gui.c +++ b/gui.c @@ -296,7 +296,7 @@ static int align_str(WINDOW* win, char *str, unsigned int len, waddstr(win, str); } else { add_spaces(win, num / 2); - waddstr(win, str[0]? str: ""); + waddstr(win, str); add_spaces(win, num - num / 2); } return 1; @@ -776,7 +776,7 @@ static void init_curses(void) { if (curses_active()) return; - if (top.win && refresh() == ERR) /* refresh is really needed */ + if (refresh() == ERR) /* refresh is really needed */ die(EXIT_FAILURE, "refresh() failed\n"); if (LINES < theme.lines_min || COLS < theme.cols_min) die(EXIT_FAILURE, "Terminal (%dx%d) too small" diff --git a/http_send.c b/http_send.c index daf39e73..9d0f49ae 100644 --- a/http_send.c +++ b/http_send.c @@ -256,12 +256,12 @@ void http_send_init(struct sender *s) s->shutdown_clients = http_shutdown_clients; s->resolve_target = NULL; s->help = generic_sender_help; - s->client_cmds[SENDER_ON] = http_com_on; - s->client_cmds[SENDER_OFF] = http_com_off; - s->client_cmds[SENDER_DENY] = http_com_deny; - s->client_cmds[SENDER_ALLOW] = http_com_allow; - s->client_cmds[SENDER_ADD] = NULL; - s->client_cmds[SENDER_DELETE] = NULL; + s->client_cmds[SENDER_on] = http_com_on; + s->client_cmds[SENDER_off] = http_com_off; + s->client_cmds[SENDER_deny] = http_com_deny; + s->client_cmds[SENDER_allow] = http_com_allow; + s->client_cmds[SENDER_add] = NULL; + s->client_cmds[SENDER_delete] = NULL; init_sender_status(hss, conf.http_access_arg, conf.http_access_given, conf.http_port_arg, conf.http_max_clients_arg, diff --git a/interactive.c b/interactive.c index 4de81d0d..ce48af32 100644 --- a/interactive.c +++ b/interactive.c @@ -31,7 +31,6 @@ struct i9e_private { struct task *task; struct btr_node *stdout_btrn; bool last_write_was_status; - bool line_handler_running; bool input_eof; bool caught_sigint; bool caught_sigterm; @@ -414,10 +413,6 @@ static void update_winsize(void) i9ep->empty_line[i9ep->num_columns] = '\0'; } -/** - * Defined key sequences are mapped to keys starting with this offset. I.e. - * pressing the first defined key sequence yields the key number \p KEY_OFFSET. - */ static int dispatch_key(__a_unused int count, __a_unused int key) { int i, ret; @@ -484,7 +479,6 @@ int i9e_open(struct i9e_client_info *ici, struct sched *s) if (ici->producer) { rl_callback_handler_install("", i9e_line_handler); i9e_attach_to_stdout(ici->producer); - rl_set_keymap(i9ep->bare_km); } else rl_callback_handler_install(i9ep->ici->prompt, i9e_line_handler); return 1; @@ -561,8 +555,6 @@ void ie9_print_status_bar(char *buf, unsigned len) * Tell i9e that the caller received a signal. * * \param sig_num The number of the signal received. - * - * Currently the function only cares about \p SIGINT, but this may change. */ void i9e_signal_dispatch(int sig_num) { diff --git a/mm.c b/mm.c index d6f3573c..92856ec3 100644 --- a/mm.c +++ b/mm.c @@ -191,6 +191,22 @@ static int mm_channels_score_function(__a_unused const char *path, return mm_compare_num_score_function(afhi->channels, private); } +static int mm_image_id_score_function(__a_unused const char *path, + const struct afs_info *afsi, + __a_unused const struct afh_info *afhi, + const void *private) +{ + return mm_compare_num_score_function(afsi->image_id, private); +} + +static int mm_lyrics_id_score_function(__a_unused const char *path, + const struct afs_info *afsi, + __a_unused const struct afh_info *afhi, + const void *private) +{ + return mm_compare_num_score_function(afsi->lyrics_id, private); +} + static int mm_num_played_score_function(__a_unused const char *path, const struct afs_info *afsi, __a_unused const struct afh_info *afhi, @@ -356,5 +372,7 @@ const struct mood_method mood_methods[] = { {DEFINE_COMPARE_NUM_MOOD_METHOD(frequency)}, {DEFINE_COMPARE_NUM_MOOD_METHOD(channels)}, {DEFINE_COMPARE_NUM_MOOD_METHOD(num_played)}, + {DEFINE_COMPARE_NUM_MOOD_METHOD(image_id)}, + {DEFINE_COMPARE_NUM_MOOD_METHOD(lyrics_id)}, {.parser = NULL} }; diff --git a/mood.c b/mood.c index d29c62c2..daa8196a 100644 --- a/mood.c +++ b/mood.c @@ -446,7 +446,7 @@ static int64_t normalized_value(int64_t x, int64_t n, int64_t sum, int64_t qd) { if (!n || !qd) return 0; - return 100 * (n * x - sum) / (int64_t)int_sqrt(n * qd); + return 100 * (n * x - sum) / (int64_t)int_sqrt(n) / (int64_t)int_sqrt(qd); } static long compute_score(struct afs_info *afsi, long mood_score) @@ -460,7 +460,7 @@ static long compute_score(struct afs_info *afsi, long mood_score) static int add_afs_statistics(const struct osl_row *row) { - uint64_t n, x, s; + uint64_t n, x, s, q; struct afs_info afsi; int ret; @@ -470,14 +470,18 @@ static int add_afs_statistics(const struct osl_row *row) n = statistics.num; x = afsi.last_played; s = statistics.last_played_sum; - if (n > 0) - statistics.last_played_qd += (x - s / n) * (x - s / n) * n / (n + 1); + if (n > 0) { + q = (x > s / n)? x - s / n : s / n - x; + statistics.last_played_qd += q * q * n / (n + 1); + } statistics.last_played_sum += x; x = afsi.num_played; s = statistics.num_played_sum; - if (n > 0) - statistics.num_played_qd += (x - s / n) * (x - s / n) * n / (n + 1); + if (n > 0) { + q = (x > s / n)? x - s / n : s / n - x; + statistics.num_played_qd += q * q * n / (n + 1); + } statistics.num_played_sum += x; statistics.num++; return 1; @@ -604,7 +608,8 @@ static int add_if_admissible(struct osl_row *aft_row, void *data) * the last number a_n was replaced by b) may be computed in O(1) time in terms * of n, q, a_n, b, and S as * - * q' = q + d * s - (2 * S + d) * d / n, + * q' = q + d * s - (2 * S + d) * d / n + * = q + d * (s - 2 * S / n - d /n), * * where d = b - a_n, and s = b + a_n. * @@ -621,7 +626,7 @@ _static_inline_ int64_t update_quadratic_deviation(int64_t n, int64_t old_qd, { int64_t delta = new_val - old_val; int64_t sigma = new_val + old_val; - return old_qd + delta * sigma - (2 * old_sum + delta) * delta / n; + return old_qd + delta * (sigma - 2 * old_sum / n - delta / n); } static int update_afs_statistics(struct afs_info *old_afsi, struct afs_info *new_afsi) diff --git a/net.c b/net.c index 463033bb..42418e5f 100644 --- a/net.c +++ b/net.c @@ -1018,7 +1018,7 @@ static void dispose_fds(int *fds, unsigned num) */ int recv_cred_buffer(int fd, char *buf, size_t size) { - char control[255]; + char control[255] __a_aligned(8); struct msghdr msg; struct cmsghdr *cmsg; struct iovec iov; diff --git a/opus_afh.c b/opus_afh.c index ace83008..e7511d36 100644 --- a/opus_afh.c +++ b/opus_afh.c @@ -96,7 +96,8 @@ static int opus_packet_callback(ogg_packet *packet, int packet_num, if (ret < 0) return ret; afhi->channels = oh->channels; - afhi->techinfo = make_message("header version %d, input sample rate: %dHz", + afhi->techinfo = make_message( + "header version %d, input sample rate: %" PRIu32 "Hz", oh->version, oh->input_sample_rate); /* * The input sample rate is irrelevant for afhi->frequency as diff --git a/opus_common.c b/opus_common.c index 927df1f3..67a8841e 100644 --- a/opus_common.c +++ b/opus_common.c @@ -104,7 +104,7 @@ int opus_parse_header(const char *packet, int len, struct opus_header *h) if (!read_chars(&p, &ch, 1)) return -E_OPUS_HEADER; h->version = ch; - if((h->version & 240) != 0) /* Only major version 0 supported. */ + if ((h->version & 240) != 0) /* Only major version 0 supported. */ return -E_OPUS_HEADER; if (!read_chars(&p, &ch, 1)) diff --git a/playlist.c b/playlist.c index 9616ed0f..01392030 100644 --- a/playlist.c +++ b/playlist.c @@ -191,8 +191,6 @@ static int handle_audio_file_event(enum afs_events event, void *data) char *new_path; const struct osl_row *row = data; - if (!current_playlist.name) - return 1; if (event == AUDIO_FILE_RENAME) { ret = row_belongs_to_score_table(row, NULL); if (ret < 0) @@ -237,7 +235,9 @@ int playlists_event_handler(enum afs_events event, int ret; struct afsi_change_event_data *aced = data; - switch(event) { + if (!current_playlist.name) + return 1; + switch (event) { case AFSI_CHANGE: return playlist_update_audio_file(aced->aft_row); case AUDIO_FILE_RENAME: diff --git a/send.h b/send.h index 09eb78ba..0c74f0ea 100644 --- a/send.h +++ b/send.h @@ -6,16 +6,21 @@ /** \file send.h Sender-related defines and structures. */ -/** The sender subcommands. */ +#define SENDER_SUBCOMMANDS \ + SENDER_SUBCOMMAND(add) /**< Add a target (udp only). */ \ + SENDER_SUBCOMMAND(delete) /**< Delete a target (udp only). */ \ + SENDER_SUBCOMMAND(allow) /**< Allow connections from given IP address(es). */ \ + SENDER_SUBCOMMAND(deny) /**< Deny connections from given IP address(es). */ \ + SENDER_SUBCOMMAND(on) /**< Activate the sender. */ \ + SENDER_SUBCOMMAND(off) /**< Deactivate the sender. */ \ + +#define SENDER_SUBCOMMAND(_name) SENDER_ ## _name, enum sender_subcommand { - SENDER_ADD, /**< Add a target (udp only). */ - SENDER_DELETE, /**< Delete a target (udp only). */ - SENDER_ALLOW, /**< Allow connections from given IP address(es). */ - SENDER_DENY, /**< Deny connections from given IP address(es). */ - SENDER_ON, /**< Activate the sender. */ - SENDER_OFF, /**< Deactivate the sender. */ + SENDER_SUBCOMMANDS NUM_SENDER_CMDS /**< Used as array size in struct \ref sender. */ }; +#undef SENDER_SUBCOMMAND +#define SENDER_SUBCOMMAND(_name) #_name, /** * Describes one supported sender of para_server. diff --git a/string.c b/string.c index c820bdca..701448e0 100644 --- a/string.c +++ b/string.c @@ -1073,7 +1073,7 @@ __must_check int strwidth(const char *s, size_t *result) return -ERRNO_TO_PARA_ERROR(errno); if (num_wchars == 0) return 0; - dest = para_malloc(num_wchars * sizeof(*dest)); + dest = para_malloc((num_wchars + 1) * sizeof(*dest)); src = s; memset(&state, 0, sizeof(state)); num_wchars = mbsrtowcs(dest, &src, num_wchars, &state); diff --git a/udp_send.c b/udp_send.c index faae208c..425118a1 100644 --- a/udp_send.c +++ b/udp_send.c @@ -46,6 +46,8 @@ struct udp_target { struct fec_client *fc; /** The FEC parameters for this target. */ struct fec_client_parms fcp; + /** Whether we already sent the FEC eof packet to this target. */ + bool sent_fec_eof; }; static struct list_head targets; @@ -54,15 +56,16 @@ static int sender_status; static void udp_close_target(struct sender_client *sc) { const char *buf; - size_t len = vss_get_fec_eof_packet(&buf); - - /* - * Ignore the return value of write() since we are closing the target - * anyway. The sole purpose of the "do_nothing" statement is to silence - * gcc. - */ - if (write(sc->fd, buf, len)) - do_nothing; + size_t len; + struct udp_target *ut = sc->private_data; + + if (ut->sent_fec_eof) + return; + PARA_NOTICE_LOG("sending FEC EOF\n"); + len = vss_get_fec_eof_packet(&buf); + /* Ignore write() errors since we are closing the target anyway. */ + if (write(sc->fd, buf, len) == len) + ut->sent_fec_eof = true; } static void udp_delete_target(struct sender_client *sc, const char *msg) @@ -187,14 +190,14 @@ static int udp_resolve_target(const char *url, struct sender_command_data *scd) static int udp_com_on(__a_unused struct sender_command_data *scd) { - sender_status = SENDER_ON; + sender_status = SENDER_on; return 1; } static int udp_com_off(__a_unused struct sender_command_data *scd) { udp_shutdown_targets(); - sender_status = SENDER_OFF; + sender_status = SENDER_off; return 1; } @@ -232,9 +235,11 @@ static int udp_com_delete(struct sender_command_data *scd) /** Initialize UDP session and set maximum payload size. */ static int udp_init_fec(struct sender_client *sc) { + struct udp_target *ut = sc->private_data; int mps; PARA_NOTICE_LOG("sending to udp %s\n", sc->name); + ut->sent_fec_eof = false; mps = generic_max_transport_msg_size(sc->fd) - sizeof(struct udphdr); PARA_INFO_LOG("current MPS = %d bytes\n", mps); return mps; @@ -277,7 +282,7 @@ static void udp_send_fec(struct sender_client *sc, char *buf, size_t len) { int ret; - if (sender_status == SENDER_OFF) + if (sender_status == SENDER_off) return; if (len == 0) return; @@ -366,7 +371,7 @@ static char *udp_status(void) "status: %s\n" "port: %s\n" "targets: %s\n", - (sender_status == SENDER_ON)? "on" : "off", + (sender_status == SENDER_on)? "on" : "off", stringify_port(conf.udp_default_port_arg, "udp"), tgts? tgts : "(none)" ); @@ -425,15 +430,15 @@ void udp_send_init(struct sender *s) s->post_select = NULL; s->shutdown_clients = udp_shutdown_targets; s->resolve_target = udp_resolve_target; - s->client_cmds[SENDER_ON] = udp_com_on; - s->client_cmds[SENDER_OFF] = udp_com_off; - s->client_cmds[SENDER_DENY] = NULL; - s->client_cmds[SENDER_ALLOW] = NULL; - s->client_cmds[SENDER_ADD] = udp_com_add; - s->client_cmds[SENDER_DELETE] = udp_com_delete; - sender_status = SENDER_OFF; + s->client_cmds[SENDER_on] = udp_com_on; + s->client_cmds[SENDER_off] = udp_com_off; + s->client_cmds[SENDER_deny] = NULL; + s->client_cmds[SENDER_allow] = NULL; + s->client_cmds[SENDER_add] = udp_com_add; + s->client_cmds[SENDER_delete] = udp_com_delete; + sender_status = SENDER_off; udp_init_target_list(); if (!conf.udp_no_autostart_given) - sender_status = SENDER_ON; + sender_status = SENDER_on; PARA_DEBUG_LOG("udp sender init complete\n"); } diff --git a/vss.c b/vss.c index cbc05d13..51db7686 100644 --- a/vss.c +++ b/vss.c @@ -905,7 +905,7 @@ static void vss_pre_select(struct sched *s, void *context) static int recv_afs_msg(int afs_socket, int *fd, uint32_t *code, uint32_t *data) { - char control[255], buf[8]; + char control[255] __a_aligned(8), buf[8]; struct msghdr msg = {.msg_iov = NULL}; struct cmsghdr *cmsg; struct iovec iov; diff --git a/web/manual.m4 b/web/manual.m4 index 4ba2f6c1..addc2458 100644 --- a/web/manual.m4 +++ b/web/manual.m4 @@ -956,12 +956,13 @@ is not set, the empty string is matched against the pattern. frequency ~ channels ~ num_played ~ + image_id ~ + lyrics_id ~ Takes a comparator ~ of the set {<, =, <=, >, >=, !=} and a number . Matches an audio file iff the condition ~ is satisfied where val is the corresponding value of the audio file -(value of the year tag, bitrate in kbit/s, frequency in Hz, channel -count, play count). +(value of the year tag, bitrate in kbit/s, etc.). The year tag is special as its value is undefined if the audio file has no year tag or the content of the year tag is not a number. Such