X-Git-Url: http://git.tuebingen.mpg.de/?p=paraslash.git;a=blobdiff_plain;f=play.c;h=14fac42fd7b6e92566815d4c56b1f4b6b23c88e2;hp=48da675ccc037f11bf9b044f232a1ecc83cc390e;hb=HEAD;hpb=e3a7e12639c34fd86d48a072beb48add8c498d09 diff --git a/play.c b/play.c index 48da675c..bd183b6b 100644 --- a/play.c +++ b/play.c @@ -7,6 +7,7 @@ #include #include "recv_cmd.lsg.h" +#include "filter_cmd.lsg.h" #include "play_cmd.lsg.h" #include "write_cmd.lsg.h" #include "play.lsg.h" @@ -24,16 +25,6 @@ #include "write.h" #include "fd.h" -/** - * Besides playback tasks which correspond to the receiver/filter/writer nodes, - * para_play creates two further tasks: The play task and the i9e task. It is - * important whether a function can be called in the context of para_play or - * i9e or both. As a rule, all command handlers are called only in i9e context via - * the line handler (input mode) or the key handler (command mode) below. - * - * Playlist handling is done exclusively in play context. - */ - /** Array of error strings. */ DEFINE_PARA_ERRLIST; @@ -117,7 +108,7 @@ INIT_STDERR_LOGGING(loglevel); char *stat_item_values[NUM_STAT_ITEMS] = {NULL}; -static struct sched sched = {.max_fileno = 0}; +static struct sched sched; static struct play_task play_task, *pt = &play_task; #define AFH_RECV_CMD (lls_cmd(LSG_RECV_CMD_CMD_AFH, recv_cmd_suite)) @@ -192,6 +183,7 @@ static char get_playback_state(void) assert(false); }; +/* returns number of milliseconds */ static long unsigned get_play_time(void) { char state = get_playback_state(); @@ -201,16 +193,16 @@ static long unsigned get_play_time(void) return 0; if (pt->num_chunks == 0 || pt->seconds == 0) return 0; - /* where the stream started (in seconds) */ - result = pt->start_chunk * pt->seconds / pt->num_chunks; + /* where the stream started (in milliseconds) */ + result = 1000ULL * pt->start_chunk * pt->seconds / pt->num_chunks; if (pt->wn.btrn) { /* Add the uptime of the writer node */ struct timeval diff = {.tv_sec = 0}, wstime; btr_get_node_start(pt->wn.btrn, &wstime); if (wstime.tv_sec > 0) tv_diff(now, &wstime, &diff); - result += diff.tv_sec; + result += tv2ms(&diff); } - result = PARA_MIN(result, pt->seconds); + result = PARA_MIN(result, pt->seconds * 1000); result = PARA_MAX(result, 0UL); return result; } @@ -238,8 +230,7 @@ static int get_playback_error(void) return 0; if (task_status(pt->rn.task) >= 0) return 0; - if (err == -E_BTR_EOF || err == -E_RECV_EOF || err == -E_EOF - || err == -E_WRITE_COMMON_EOF) + if (err == -E_EOF) return 1; return err; } @@ -265,6 +256,7 @@ static int eof_cleanup(void) if (decoder->close) decoder->close(&pt->fn); btr_remove_node(&pt->fn.btrn); + lls_free_parse_result(pt->fn.lpr, FILTER_CMD(pt->fn.filter_num)); free(pt->fn.conf); memset(&pt->fn, 0, sizeof(struct filter_node)); @@ -288,7 +280,7 @@ static int shuffle_compare(__a_unused const void *a, __a_unused const void *b) static void init_shuffle_map(void) { unsigned n, num_inputs = lls_num_inputs(play_lpr); - shuffle_map = para_malloc(num_inputs * sizeof(unsigned)); + shuffle_map = arr_alloc(num_inputs, sizeof(unsigned)); for (n = 0; n < num_inputs; n++) shuffle_map[n] = n; if (!OPT_GIVEN(RANDOMIZE)) @@ -591,7 +583,7 @@ static char *get_user_key_map_seq(int key) if (!p) return NULL; len = p - kma; - result = para_malloc(len + 1); + result = alloc(len + 1); memcpy(result, kma, len); result[len] = '\0'; return result; @@ -611,7 +603,7 @@ static char *get_key_map_seq_safe(int key) if (len == 1 && isprint(*seq)) return seq; - sseq = para_malloc(2 + 2 * len + 1); + sseq = alloc(2 + 2 * len + 1); sseq[0] = '0'; sseq[1] = 'x'; for (n = 0; n < len; n++) { @@ -651,7 +643,7 @@ static char **get_mapped_keyseqs(void) char **result; int i; - result = para_malloc((NUM_MAPPED_KEYS + 1) * sizeof(char *)); + result = arr_alloc(NUM_MAPPED_KEYS + 1, sizeof(char *)); FOR_EACH_MAPPED_KEY(i) { char *seq = get_key_map_seq(i); result[i] = seq; @@ -840,20 +832,20 @@ EXPORT_PLAY_CMD_HANDLER(play); static int com_pause(__a_unused struct lls_parse_result *lpr) { char state; - long unsigned seconds, ss; + uint64_t ms; + unsigned long cn; /* chunk num */ state = get_playback_state(); pt->playing = false; if (state != 'P') return 0; - seconds = get_play_time(); + ms = get_play_time(); pt->playing = false; - ss = 0; + cn = 0; if (pt->seconds > 0) - ss = seconds * pt->num_chunks / pt->seconds + 1; - ss = PARA_MAX(ss, 0UL); - ss = PARA_MIN(ss, pt->num_chunks); - pt->start_chunk = ss; + cn = ms * pt->num_chunks / pt->seconds / 1000 + 1; + cn = PARA_MIN(cn, pt->num_chunks); + pt->start_chunk = cn; pt->rq = CRT_REPOS; kill_stream(); return 0; @@ -953,7 +945,7 @@ static int com_ff(struct lls_parse_result *lpr) return ret; if (pt->playing && !pt->fn.btrn) return 0; - seconds += get_play_time(); + seconds += (get_play_time() + 500) / 1000; seconds = PARA_MIN(seconds, (typeof(seconds))pt->seconds - 4); seconds = PARA_MAX(seconds, 0); pt->start_chunk = pt->num_chunks * seconds / pt->seconds; @@ -1056,9 +1048,9 @@ static void session_open(void) char *dot_para = make_message("%s/.paraslash", home); free(home); - ret = para_mkdir(dot_para, 0777); + ret = para_mkdir(dot_para); /* warn, but otherwise ignore mkdir error */ - if (ret < 0 && ret != -ERRNO_TO_PARA_ERROR(EEXIST)) + if (ret < 0) PARA_WARNING_LOG("Can not create %s: %s\n", dot_para, para_strerror(-ret)); history_file = make_message("%s/play.history", dot_para); @@ -1075,7 +1067,7 @@ static void session_open(void) sigemptyset(&act.sa_mask); act.sa_flags = 0; sigaction(SIGWINCH, &act, NULL); - sched.select_function = i9e_select; + sched.poll_function = i9e_poll; ici.bound_keyseqs = get_mapped_keyseqs(); pt->btrn = ici.producer = btr_new_node(&(struct btr_node_description) @@ -1188,7 +1180,7 @@ static unsigned get_time_string(char **result) length = pt->seconds; if (length == 0) return xasprintf(result, "0:00 [0:00] (0%%/0:00)"); - seconds = get_play_time(); + seconds = (get_play_time() + 500) / 1000; return xasprintf(result, "#%u: %d:%02d [%d:%02d] (%d%%/%d:%02d) %s", pt->current_file, seconds / 60, @@ -1245,10 +1237,25 @@ out: /** * The main function of para_play. * - * \param argc Standard. - * \param argv Standard. + * \param argc See man page. + * \param argv See man page. + * + * para_play distributes its work by submitting various tasks to the paraslash + * scheduler. The receiver, filter and writer tasks, which are used to play an + * audio file, require one task each to maintain their underlying buffer tree + * node. These tasks only exist when an audio file is playing. + * + * The i9 task, which is submitted and maintained by the i9e subsystem, reads + * an input line and calls the corresponding command handler such as com_stop() + * which is implemented in this file. The command handlers typically write a + * request to the global play_task structure, whose contents are read and acted + * upon by another task, the play task. + * + * As a rule, playlist handling is performed exclusively in play context, i.e. + * in the post-monitor step of the play task, while command handlers are only + * called in i9e context. * - * \return \p EXIT_FAILURE or \p EXIT_SUCCESS. + * \return EXIT_FAILURE or EXIT_SUCCESS. */ int main(int argc, char *argv[]) { @@ -1260,7 +1267,7 @@ int main(int argc, char *argv[]) session_open(); num_inputs = lls_num_inputs(play_lpr); init_shuffle_map(); - pt->invalid = para_calloc(sizeof(*pt->invalid) * num_inputs); + pt->invalid = arr_zalloc(num_inputs, sizeof(*pt->invalid)); pt->rq = CRT_FILE_CHANGE; pt->playing = true; pt->task = task_register(&(struct task_info){