2 * Copyright (C) 1998-2013 Andre Noll <maan@systemlinux.org>
4 * Licensed under the GPL v2. For licencing details see COPYING.
7 /** \file fade.c A volume fader and alarm clock for OSS. */
11 #include "fade.cmdline.h"
21 static struct fade_args_info conf
;
23 enum mixer_id
{MIXER_ENUM
};
24 static char *mixer_name
[] = {MIXER_NAMES
};
26 static struct mixer supported_mixer
[] = {MIXER_ARRAY
};
27 #define FOR_EACH_MIXER(i) for ((i) = 0; (i) < NUM_SUPPORTED_MIXERS; (i)++)
30 static __printf_2_3
void date_log(int ll
, const char *fmt
, ...)
40 fprintf(stderr
, "%d:%02d:%02d ", tm
->tm_hour
, tm
->tm_min
, tm
->tm_sec
);
45 __printf_2_3
void (*para_log
)(int, const char*, ...) = date_log
;
47 static int set_channel(struct mixer
*m
, struct mixer_handle
*h
, const char *channel
)
52 ret
= m
->set_channel(h
, channel
);
54 PARA_NOTICE_LOG("using %s mixer channel\n",
55 channel
? channel
: "default");
58 channels
= m
->get_channels(h
);
59 printf("Available channels: %s\n", channels
);
64 /* Fade to new volume in fade_time seconds. */
65 static int fade(struct mixer
*m
, struct mixer_handle
*h
, int new_vol
, int fade_time
)
67 int vol
, diff
, incr
, ret
;
70 unsigned long long tmp
, tmp2
; /* Careful with that axe, Eugene! */
73 return m
->set(h
, new_vol
);
79 PARA_NOTICE_LOG("fading %s from %d to %d in %d seconds\n",
80 conf
.mixer_channel_arg
, vol
, new_vol
, secs
);
86 incr
= diff
> 0? 1: -1;
87 diff
= diff
> 0? diff
: -diff
;
88 tmp
= secs
* 1000 / diff
;
90 while ((new_vol
- vol
) * incr
> 0) {
91 ts
.tv_nsec
= tmp2
* 1000000; /* really nec ?*/
92 ts
.tv_sec
= tmp
/ 1000; /* really nec ?*/
93 //printf("ts.tv_sec: %i\n", ts.tv_nsec);
98 //printf("vol = %i\n", vol);
105 static void client_cmd(const char *cmd
)
107 int ret
, status
, fds
[3] = {0, 0, 0};
109 char *cmdline
= make_message(BINDIR
"/para_client %s", cmd
);
111 PARA_NOTICE_LOG("%s\n", cmdline
);
112 ret
= para_exec_cmdline_pid(&pid
, cmdline
, fds
);
115 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
119 pid
= waitpid(pid
, &status
, 0);
120 while (pid
== -1 && errno
== EINTR
);
122 PARA_ERROR_LOG("%s\n", strerror(errno
));
125 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
129 PARA_EMERG_LOG("command \"%s\" failed\n", cmd
);
133 static void change_afs_mode_and_play(char *afs_mode
)
140 cmd
= make_message("select %s", afs_mode
);
146 static int set_initial_volume(struct mixer
*m
, struct mixer_handle
*h
)
150 for (i
= 0; i
< conf
.ivol_given
; i
++) {
151 char *p
, *ch
, *arg
= para_strdup(conf
.ivol_arg
[i
]);
153 p
= strchr(arg
, ':');
162 ret
= para_atoi32(p
, &iv
);
167 ret
= set_channel(m
, h
, ch
);
171 PARA_WARNING_LOG("ignoring channel %s\n", ch
);
174 PARA_INFO_LOG("initial volume %s: %d\n", ch
, iv
);
184 static int sweet_dreams(struct mixer
*m
, struct mixer_handle
*h
)
186 time_t t1
, wake_time_epoch
;
189 int ret
, min
= conf
.wake_min_arg
;
190 char *fo_mood
= conf
.fo_mood_arg
;
191 char *fi_mood
= conf
.fi_mood_arg
;
192 char *sleep_mood
= conf
.sleep_mood_arg
;
193 int fit
= conf
.fi_time_arg
;
194 int fot
= conf
.fo_time_arg
;
195 int fiv
= conf
.fi_vol_arg
;
196 int fov
= conf
.fo_vol_arg
;
198 /* calculate wake time */
200 if (conf
.wake_hour_given
) {
201 int hour
= conf
.wake_hour_arg
;
203 if (tm
->tm_hour
> hour
|| (tm
->tm_hour
== hour
&& tm
->tm_min
> min
)) {
204 t1
+= 86400; /* wake time is tomorrow */
211 t1
+= 9 * 60 * 60; /* nine hours from now */
212 PARA_INFO_LOG("default wake time: %lu\n", (long unsigned)t1
);
215 wake_time_epoch
= mktime(tm
);
216 PARA_INFO_LOG("waketime: %s", asctime(tm
));
220 ret
= set_initial_volume(m
, h
);
223 change_afs_mode_and_play(fo_mood
);
224 ret
= set_channel(m
, h
, conf
.mixer_channel_arg
);
227 ret
= fade(m
, h
, fov
, fot
);
231 ret
= m
->set(h
, fov
);
235 if (conf
.sleep_mood_given
)
236 change_afs_mode_and_play(sleep_mood
);
243 if (wake_time_epoch
<= t1
+ fit
)
245 delay
= wake_time_epoch
- t1
- fit
;
246 PARA_INFO_LOG("sleeping %u seconds (%u:%02u)\n",
248 (delay
% 3600) / 60);
251 change_afs_mode_and_play(fi_mood
);
252 ret
= fade(m
, h
, fiv
, fit
);
253 PARA_INFO_LOG("fade complete, returning\n");
257 static int snooze(struct mixer
*m
, struct mixer_handle
*h
)
261 if (conf
.so_time_arg
<= 0)
267 if (val
< conf
.so_vol_arg
)
268 ret
= m
->set(h
, conf
.so_vol_arg
);
270 ret
= fade(m
, h
, conf
.so_vol_arg
, conf
.so_time_arg
);
274 PARA_NOTICE_LOG("%d seconds snooze time...\n", conf
.snooze_time_arg
);
275 sleep(conf
.snooze_time_arg
);
277 return fade(m
, h
, conf
.si_vol_arg
, conf
.si_time_arg
);
280 static int configfile_exists(void)
282 static char *config_file
;
284 if (!conf
.config_file_given
) {
285 char *home
= para_homedir();
287 config_file
= make_message("%s/.paraslash/fade.conf", home
);
289 conf
.config_file_arg
= config_file
;
291 return file_exists(conf
.config_file_arg
);
294 static void init_mixers(void)
299 struct mixer
*m
= &supported_mixer
[i
];
300 PARA_DEBUG_LOG("initializing mixer API #%d (%s)\n",
306 static int set_val(struct mixer
*m
, struct mixer_handle
*h
)
308 return m
->set(h
, conf
.val_arg
);
311 static struct mixer
*get_mixer_or_die(void)
315 if (!conf
.mixer_api_given
)
319 if (!strcmp(mixer_name
[i
], conf
.mixer_api_arg
))
321 if (i
< NUM_SUPPORTED_MIXERS
) {
322 PARA_NOTICE_LOG("using %s mixer API\n", mixer_name
[i
]);
323 return supported_mixer
+ i
;
325 printf("available mixer APIs: ");
327 int d
= (i
== DEFAULT_MIXER
);
328 printf("%s%s%s ", d
? "[" : "", mixer_name
[i
], d
? "]" : "");
334 __noreturn
static void print_help_and_die(void)
336 struct ggo_help h
= DEFINE_GGO_HELP(fade
);
337 bool d
= conf
.detailed_help_given
;
339 ggo_print_help(&h
, d
? GPH_STANDARD_FLAGS_DETAILED
: GPH_STANDARD_FLAGS
);
343 int main(int argc
, char *argv
[])
347 struct mixer_handle
*h
= NULL
;
349 fade_cmdline_parser(argc
, argv
, &conf
);
350 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
351 version_handle_flag("fade", conf
.version_given
);
352 if (conf
.help_given
|| conf
.detailed_help_given
)
353 print_help_and_die();
354 ret
= configfile_exists();
355 if (!ret
&& conf
.config_file_given
) {
356 PARA_EMERG_LOG("can not read config file %s\n",
357 conf
.config_file_arg
);
361 struct fade_cmdline_parser_params params
= {
365 .check_ambiguity
= 0,
368 fade_cmdline_parser_config_file(conf
.config_file_arg
,
370 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
373 m
= get_mixer_or_die();
374 ret
= m
->open(conf
.mixer_device_arg
, &h
);
377 ret
= set_channel(m
, h
, conf
.mixer_channel_arg
);
380 switch (conf
.mode_arg
) {
382 ret
= fade(m
, h
, conf
.fade_vol_arg
, conf
.fade_time_arg
);
384 case mode_arg_snooze
:
390 default: /* sleep mode */
391 ret
= sweet_dreams(m
, h
);
397 PARA_EMERG_LOG("%s\n", para_strerror(-ret
));
398 return ret
< 0? EXIT_FAILURE
: EXIT_SUCCESS
;