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 printf("%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 /* Fade to new volume in fade_time seconds. */
48 static int fade(struct mixer
*m
, struct mixer_handle
*h
, int new_vol
, int fade_time
)
50 int vol
, diff
, incr
, ret
;
53 unsigned long long tmp
, tmp2
; /* Careful with that axe, Eugene! */
56 return m
->set(h
, new_vol
);
58 PARA_NOTICE_LOG("fading to %d in %d seconds\n", new_vol
, secs
);
68 incr
= diff
> 0? 1: -1;
69 diff
= diff
> 0? diff
: -diff
;
70 tmp
= secs
* 1000 / diff
;
72 while ((new_vol
- vol
) * incr
> 0) {
73 ts
.tv_nsec
= tmp2
* 1000000; /* really nec ?*/
74 ts
.tv_sec
= tmp
/ 1000; /* really nec ?*/
75 //printf("ts.tv_sec: %i\n", ts.tv_nsec);
80 //printf("vol = %i\n", vol);
87 static void client_cmd(const char *cmd
)
89 int ret
, status
, fds
[3] = {0, 0, 0};
91 char *cmdline
= make_message(BINDIR
"/para_client %s", cmd
);
93 PARA_NOTICE_LOG("%s\n", cmdline
);
94 ret
= para_exec_cmdline_pid(&pid
, cmdline
, fds
);
97 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
101 pid
= waitpid(pid
, &status
, 0);
102 while (pid
== -1 && errno
== EINTR
);
104 PARA_ERROR_LOG("%s\n", strerror(errno
));
107 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
111 PARA_EMERG_LOG("command \"%s\" failed\n", cmd
);
115 static void change_afs_mode_and_play(char *afs_mode
)
122 cmd
= make_message("select %s", afs_mode
);
128 static int sweet_dreams(struct mixer
*m
, struct mixer_handle
*h
)
130 time_t t1
, wake_time_epoch
;
133 int ret
, min
= conf
.wake_min_arg
;
134 char *fo_mood
= conf
.fo_mood_arg
;
135 char *fi_mood
= conf
.fi_mood_arg
;
136 char *sleep_mood
= conf
.sleep_mood_arg
;
137 int fit
= conf
.fi_time_arg
;
138 int fot
= conf
.fo_time_arg
;
139 int fiv
= conf
.fi_vol_arg
;
140 int fov
= conf
.fo_vol_arg
;
141 int iv
= conf
.ivol_arg
;
143 /* calculate wake time */
145 if (conf
.wake_hour_given
) {
146 int hour
= conf
.wake_hour_arg
;
148 if (tm
->tm_hour
> hour
|| (tm
->tm_hour
== hour
&& tm
->tm_min
> min
)) {
149 t1
+= 86400; /* wake time is tomorrow */
156 t1
+= 9 * 60 * 60; /* nine hours from now */
157 PARA_INFO_LOG("default wake time: %lu\n", (long unsigned)t1
);
160 wake_time_epoch
= mktime(tm
);
161 PARA_INFO_LOG("waketime: %s", asctime(tm
));
165 PARA_INFO_LOG("initial volume: %d\n", iv
);
169 change_afs_mode_and_play(fo_mood
);
170 ret
= fade(m
, h
, fov
, fot
);
174 ret
= m
->set(h
, fov
);
178 if (conf
.sleep_mood_given
)
179 change_afs_mode_and_play(sleep_mood
);
186 if (wake_time_epoch
<= t1
+ fit
)
188 delay
= wake_time_epoch
- t1
- fit
;
189 PARA_INFO_LOG("sleeping %u seconds (%u:%02u)\n",
191 (delay
% 3600) / 60);
194 change_afs_mode_and_play(fi_mood
);
195 ret
= fade(m
, h
, fiv
, fit
);
196 PARA_INFO_LOG("fade complete, returning\n");
200 static int snooze(struct mixer
*m
, struct mixer_handle
*h
)
204 if (conf
.so_time_arg
<= 0)
210 if (val
< conf
.so_vol_arg
)
211 ret
= m
->set(h
, conf
.so_vol_arg
);
213 ret
= fade(m
, h
, conf
.so_vol_arg
, conf
.so_time_arg
);
217 PARA_NOTICE_LOG("%d seconds snooze time...\n", conf
.snooze_time_arg
);
218 sleep(conf
.snooze_time_arg
);
220 return fade(m
, h
, conf
.si_vol_arg
, conf
.si_time_arg
);
223 static int configfile_exists(void)
225 static char *config_file
;
227 if (!conf
.config_file_given
) {
228 char *home
= para_homedir();
230 config_file
= make_message("%s/.paraslash/fade.conf", home
);
232 conf
.config_file_arg
= config_file
;
234 return file_exists(conf
.config_file_arg
);
237 static void init_mixers(void)
242 struct mixer
*m
= &supported_mixer
[i
];
243 PARA_DEBUG_LOG("initializing mixer API #%d (%s)\n",
249 static int set_channel(struct mixer
*m
, struct mixer_handle
*h
)
254 ret
= m
->set_channel(h
, conf
.mixer_channel_arg
);
256 PARA_NOTICE_LOG("using %s mixer channel\n",
257 conf
.mixer_channel_arg
? conf
.mixer_channel_arg
261 channels
= m
->get_channels(h
);
262 printf("Available channels: %s\n", channels
);
267 static struct mixer
*get_mixer_or_die(void)
271 if (!conf
.mixer_api_given
)
275 if (!strcmp(mixer_name
[i
], conf
.mixer_api_arg
))
277 if (i
< NUM_SUPPORTED_MIXERS
) {
278 PARA_NOTICE_LOG("using %s mixer API\n", mixer_name
[i
]);
279 return supported_mixer
+ i
;
281 printf("available mixer APIs: ");
283 int d
= (i
== DEFAULT_MIXER
);
284 printf("%s%s%s ", d
? "[" : "", mixer_name
[i
], d
? "]" : "");
290 __noreturn
static void print_help_and_die(void)
292 struct ggo_help h
= DEFINE_GGO_HELP(fade
);
293 bool d
= conf
.detailed_help_given
;
295 ggo_print_help(&h
, d
? GPH_STANDARD_FLAGS_DETAILED
: GPH_STANDARD_FLAGS
);
299 int main(int argc
, char *argv
[])
303 struct mixer_handle
*h
= NULL
;
305 fade_cmdline_parser(argc
, argv
, &conf
);
306 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
307 version_handle_flag("fade", conf
.version_given
);
308 if (conf
.help_given
|| conf
.detailed_help_given
)
309 print_help_and_die();
310 ret
= configfile_exists();
311 if (!ret
&& conf
.config_file_given
) {
312 PARA_EMERG_LOG("can not read config file %s\n",
313 conf
.config_file_arg
);
317 struct fade_cmdline_parser_params params
= {
321 .check_ambiguity
= 0,
324 fade_cmdline_parser_config_file(conf
.config_file_arg
,
326 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
329 m
= get_mixer_or_die();
330 ret
= m
->open(conf
.mixer_device_arg
, &h
);
333 ret
= set_channel(m
, h
);
336 switch (conf
.mode_arg
) {
338 ret
= fade(m
, h
, conf
.fade_vol_arg
, conf
.fade_time_arg
);
340 case mode_arg_snooze
:
343 default: /* sleep mode */
344 ret
= sweet_dreams(m
, h
);
350 PARA_EMERG_LOG("%s\n", para_strerror(-ret
));
351 return ret
< 0? EXIT_FAILURE
: EXIT_SUCCESS
;