Merge branch 'refs/heads/t/para_play'
[paraslash.git] / mixer.c
diff --git a/mixer.c b/mixer.c
index 0c08e2f6d0ab24f35334aa9961bb2f143e656235..eae8929164770053c5c18843f4cf4e4e8bc5e616 100644 (file)
--- a/mixer.c
+++ b/mixer.c
@@ -1,10 +1,6 @@
-/*
- * Copyright (C) 1998 Andre Noll <maan@tuebingen.mpg.de>
- *
- * Licensed under the GPL v2. For licencing details see COPYING.
- */
+/* Copyright (C) 1998 Andre Noll <maan@tuebingen.mpg.de>, see file COPYING. */
 
-/** \file mixer.c A volume fader and alarm clock for OSS. */
+/** \file mixer.c A volume fader and alarm clock. */
 
 #include <regex.h>
 #include <lopsub.h>
@@ -12,6 +8,7 @@
 
 #include "mixer.lsg.h"
 #include "para.h"
+#include "lsu.h"
 #include "fd.h"
 #include "string.h"
 #include "mix.h"
@@ -43,7 +40,7 @@ static struct lls_parse_result *lpr, *sub_lpr;
 #define OPT_STRING_VAL(_cmd, _opt) (lls_string_val(0, OPT_RESULT(_cmd, _opt)))
 #define OPT_UINT32_VAL(_cmd, _opt) (lls_uint32_val(0, OPT_RESULT(_cmd, _opt)))
 
-typedef int (*mixer_subcommand_handler_t)(const struct mixer *, struct mixer_handle *);
+typedef int (*mixer_subcommand_handler_t)(const struct mixer *);
 
 #define EXPORT_CMD(_cmd) const mixer_subcommand_handler_t \
        lsg_mixer_com_ ## _cmd ## _user_data = &com_ ## _cmd;
@@ -156,11 +153,37 @@ sleep:
        return ret;
 }
 
-static int com_fade(const struct mixer *m, struct mixer_handle *h)
+static int open_mixer_and_set_channel(const struct mixer *m, struct mixer_handle **h)
+{
+       int ret;
+
+       ret = m->open(OPT_STRING_VAL(PARA_MIXER, MIXER_DEVICE), h);
+       if (ret < 0)
+               return ret;
+       ret = set_channel(m, *h, OPT_STRING_VAL(PARA_MIXER, MIXER_CHANNEL));
+       if (ret == -E_BAD_CHANNEL) {
+               char *channels = m->get_channels(*h);
+               printf("Available channels: %s\n", channels);
+               free(channels);
+       }
+       if (ret < 0)
+               m->close(h);
+       return ret;
+}
+
+static int com_fade(const struct mixer *m)
 {
        uint32_t new_vol = OPT_UINT32_VAL(FADE, FADE_VOL);
        uint32_t fade_time = OPT_UINT32_VAL(FADE, FADE_TIME);
-       return fade(m, h, new_vol, fade_time);
+       struct mixer_handle *h;
+       int ret;
+
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               return ret;
+       ret = fade(m, h, new_vol, fade_time);
+       m->close(&h);
+       return ret;
 }
 EXPORT_CMD(fade);
 
@@ -196,9 +219,6 @@ static void change_afs_mode(const char *afs_mode)
 {
        char *cmd;
 
-       client_cmd("stop");
-       if (!afs_mode)
-               return;
        cmd = make_message("select %s", afs_mode);
        client_cmd(cmd);
        free(cmd);
@@ -243,7 +263,7 @@ static int set_initial_volume(const struct mixer *m, struct mixer_handle *h)
        return 1;
 }
 
-static int com_sleep(const struct mixer *m, struct mixer_handle *h)
+static int com_sleep(const struct mixer *m)
 {
        time_t t1, wake_time_epoch;
        unsigned int delay;
@@ -258,9 +278,13 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h)
        int fiv = OPT_UINT32_VAL(SLEEP, FI_VOL);
        int fov = OPT_UINT32_VAL(SLEEP, FO_VOL);
        int32_t hour, min = 0;
-       char *tmp;
-       char *wt = para_strdup(wake_time + (wake_time[0] == '+'));
+       char *tmp, *wt;
+       struct mixer_handle *h;
 
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               return ret;
+       wt = para_strdup(wake_time + (wake_time[0] == '+'));
        /* calculate wake time */
        time(&t1);
        tmp = strchr(wt, ':');
@@ -270,13 +294,13 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h)
                ret = para_atoi32(tmp, &min);
                if (ret < 0) {
                        free(wt);
-                       return ret;
+                       goto close_mixer;
                }
        }
        ret = para_atoi32(wt, &hour);
        free(wt);
        if (ret < 0)
-               return ret;
+               goto close_mixer;
        if (wake_time[0] == '+') { /* relative */
                t1 += hour * 60 * 60 + min * 60;
                tm = localtime(&t1);
@@ -294,31 +318,32 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h)
        PARA_INFO_LOG("waketime: %d:%02d\n", tm->tm_hour, tm->tm_min);
        client_cmd("stop");
        sleep(1);
-       if (fot) {
+       if (fot && fo_mood && *fo_mood) {
                ret = set_initial_volume(m, h);
                if (ret < 0)
-                       return ret;
+                       goto close_mixer;
                change_afs_mode(fo_mood);
                client_cmd("play");
                ret = set_channel(m, h, OPT_STRING_VAL(PARA_MIXER, MIXER_CHANNEL));
                if (ret < 0)
-                       return ret;
+                       goto close_mixer;
                ret = fade(m, h, fov, fot);
                if (ret < 0)
-                       return ret;
+                       goto close_mixer;
        } else {
                ret = m->set(h, fov);
                if (ret < 0)
-                       return ret;
+                       goto close_mixer;
        }
-       if (OPT_GIVEN(SLEEP, SLEEP_MOOD)) {
+       if (sleep_mood && *sleep_mood) {
                change_afs_mode(sleep_mood);
-               client_cmd("play");
-       } else
+               if (!fot || !fo_mood) /* currently stopped */
+                       client_cmd("play");
+       } else if (fot && fo_mood && *fo_mood) /* currently playing */
                client_cmd("stop");
-       if (!fit)
+       m->close(&h);
+       if (!fit || !fi_mood || !*fi_mood) /* nothing to do */
                return 1;
-       change_afs_mode(fi_mood);
        for (;;) {
                time(&t1);
                if (wake_time_epoch <= t1 + fit)
@@ -329,22 +354,35 @@ static int com_sleep(const struct mixer *m, struct mixer_handle *h)
                        (delay % 3600) / 60);
                sleep(delay);
        }
-       client_cmd("play");
+       change_afs_mode(fi_mood);
+       if (sleep_mood && *sleep_mood) /* currently playing */
+               client_cmd("next");
+       else /* currently stopped */
+               client_cmd("play");
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               return ret;
        ret = fade(m, h, fiv, fit);
-       PARA_INFO_LOG("fade complete, returning\n");
+close_mixer:
+       m->close(&h);
        return ret;
 }
 EXPORT_CMD(sleep);
 
-static int com_snooze(const struct mixer *m, struct mixer_handle *h)
+static int com_snooze(const struct mixer *m)
 {
        int ret, val;
+       struct mixer_handle *h;
 
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               return ret;
+       ret = 1;
        if (OPT_UINT32_VAL(SNOOZE, SO_TIME) == 0)
-               return 1;
+               goto close_mixer;
        ret = m->get(h);
        if (ret < 0)
-               return ret;
+               goto close_mixer;
        val = ret;
        if (val < OPT_UINT32_VAL(SNOOZE, SO_VOL))
                ret = m->set(h, OPT_UINT32_VAL(SNOOZE, SO_VOL));
@@ -352,20 +390,35 @@ static int com_snooze(const struct mixer *m, struct mixer_handle *h)
                ret = fade(m, h, OPT_UINT32_VAL(SNOOZE, SO_VOL),
                        OPT_UINT32_VAL(SNOOZE, SO_TIME));
        if (ret < 0)
-               return ret;
+               goto close_mixer;
        client_cmd("pause");
        PARA_NOTICE_LOG("%" PRIu32 " seconds snooze time...\n",
                OPT_UINT32_VAL(SNOOZE, SNOOZE_TIME));
+       m->close(&h);
        sleep(OPT_UINT32_VAL(SNOOZE, SNOOZE_TIME));
        client_cmd("play");
-       return fade(m, h, OPT_UINT32_VAL(SNOOZE, SI_VOL),
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               goto close_mixer;
+       ret = fade(m, h, OPT_UINT32_VAL(SNOOZE, SI_VOL),
                OPT_UINT32_VAL(SNOOZE, SI_TIME));
+close_mixer:
+       m->close(&h);
+       return ret;
 }
 EXPORT_CMD(snooze);
 
-static int com_set(const struct mixer *m, struct mixer_handle *h)
+static int com_set(const struct mixer *m)
 {
-       return m->set(h, OPT_UINT32_VAL(SET, VAL));
+       struct mixer_handle *h;
+       int ret;
+
+       ret = open_mixer_and_set_channel(m, &h);
+       if (ret < 0)
+               return ret;
+       ret = m->set(h, OPT_UINT32_VAL(SET, VAL));
+       m->close(&h);
+       return ret;
 }
 EXPORT_CMD(set);
 
@@ -404,9 +457,7 @@ static void show_subcommands(void)
        }
 }
 
-
-static int com_help(__a_unused const struct mixer *m,
-               __a_unused struct mixer_handle *h)
+static int com_help(__a_unused const struct mixer *m)
 {
        const struct lls_command *cmd;
        const struct lls_opt_result *r_l = OPT_RESULT(HELP, LONG);
@@ -459,60 +510,16 @@ static void handle_help_flags(void)
 static int parse_and_merge_config_file(const struct lls_command *cmd)
 {
        int ret;
-       int cf_argc;
-       char **cf_argv;
-       char *cf, *errctx = NULL;
-       struct lls_parse_result **lprp, *cf_lpr, *merged_lpr;
-       void *map;
-       size_t sz;
-       const char *subcmd_name;
-
-       if (cmd == lls_cmd(0, mixer_suite)) {
-               lprp = &lpr;
-               subcmd_name = NULL;
-       } else {
-               lprp = &sub_lpr;
-               subcmd_name = lls_command_name(cmd);
-       }
-       if (OPT_GIVEN(PARA_MIXER, CONFIG_FILE))
-               cf = para_strdup(OPT_STRING_VAL(PARA_MIXER, CONFIG_FILE));
-       else {
-               char *home = para_homedir();
-               cf = make_message("%s/.paraslash/mixer.conf", home);
-               free(home);
-       }
-       ret = mmap_full_file(cf, O_RDONLY, &map, &sz, NULL);
-       if (ret < 0) {
-               if (ret != -E_EMPTY && ret != -ERRNO_TO_PARA_ERROR(ENOENT))
-                       goto free_cf;
-               if (ret == -ERRNO_TO_PARA_ERROR(ENOENT) &&
-                               OPT_GIVEN(PARA_MIXER, CONFIG_FILE))
-                       goto free_cf;
-       } else {
-               ret = lls(lls_convert_config(map, sz, subcmd_name, &cf_argv, &errctx));
-               para_munmap(map, sz);
-               if (ret < 0)
-                       goto free_cf;
-               cf_argc = ret;
-               ret = lls(lls_parse(cf_argc, cf_argv, cmd, &cf_lpr, &errctx));
-               lls_free_argv(cf_argv);
-               if (ret < 0)
-                       goto free_cf;
-               ret = lls(lls_merge(*lprp, cf_lpr, cmd, &merged_lpr, &errctx));
-               lls_free_parse_result(cf_lpr, cmd);
-               if (ret < 0)
-                       goto free_cf;
-               lls_free_parse_result(*lprp, cmd);
-               *lprp = merged_lpr;
-               loglevel = OPT_UINT32_VAL(PARA_MIXER, LOGLEVEL);
-       }
-       ret = 1;
-free_cf:
-       free(cf);
-       if (errctx)
-               PARA_ERROR_LOG("%s\n", errctx);
-       free(errctx);
-       return ret;
+       struct lls_parse_result **lprp = (cmd == lls_cmd(0, mixer_suite))?
+               &lpr : &sub_lpr;
+
+       ret = lsu_merge_config_file_options(OPT_STRING_VAL(PARA_MIXER,
+               CONFIG_FILE), "mixer.conf", lprp, cmd, mixer_suite,
+               0 /* flags */);
+       if (ret < 0)
+               return ret;
+       loglevel = OPT_UINT32_VAL(PARA_MIXER, LOGLEVEL);
+       return 1;
 }
 
 /**
@@ -533,7 +540,6 @@ int main(int argc, char *argv[])
        char *errctx;
        const char *subcmd;
        const struct mixer *m;
-       struct mixer_handle *h;
        unsigned n;
 
        ret = lls(lls_parse(argc, argv, cmd, &lpr, &errctx));
@@ -561,23 +567,10 @@ int main(int argc, char *argv[])
        if (ret < 0)
                goto free_lpr;
        ret = parse_and_merge_config_file(cmd);
-       if (ret < 0)
-               goto free_lpr;
-       m = get_mixer_or_die();
-       ret = m->open(OPT_STRING_VAL(PARA_MIXER, MIXER_DEVICE), &h);
        if (ret < 0)
                goto free_sub_lpr;
-       ret = set_channel(m, h, OPT_STRING_VAL(PARA_MIXER, MIXER_CHANNEL));
-       if (ret == -E_BAD_CHANNEL) {
-               char *channels = m->get_channels(h);
-               printf("Available channels: %s\n", channels);
-               free(channels);
-       }
-       if (ret < 0)
-               goto close_mixer;
-       ret = (*(mixer_subcommand_handler_t *)(lls_user_data(cmd)))(m ,h);
-close_mixer:
-       m->close(&h);
+       m = get_mixer_or_die();
+       ret = (*(mixer_subcommand_handler_t *)(lls_user_data(cmd)))(m);
 free_sub_lpr:
        lls_free_parse_result(sub_lpr, cmd);
 free_lpr: