2 * Copyright (C) 1998 Andre Noll <maan@tuebingen.mpg.de>
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
)
50 PARA_NOTICE_LOG("using %s mixer channel\n", channel
?
52 return m
->set_channel(h
, channel
);
55 /* Fade to new volume in fade_time seconds. */
56 static int fade(struct mixer
*m
, struct mixer_handle
*h
, int new_vol
, int fade_time
)
58 int vol
, diff
, incr
, ret
;
61 unsigned long long tmp
, tmp2
; /* Careful with that axe, Eugene! */
64 return m
->set(h
, new_vol
);
70 PARA_NOTICE_LOG("fading %s from %d to %d in %d seconds\n",
71 conf
.mixer_channel_arg
, vol
, new_vol
, secs
);
77 incr
= diff
> 0? 1: -1;
78 diff
= diff
> 0? diff
: -diff
;
79 tmp
= secs
* 1000 / diff
;
81 while ((new_vol
- vol
) * incr
> 0) {
82 ts
.tv_nsec
= tmp2
* 1000000; /* really nec ?*/
83 ts
.tv_sec
= tmp
/ 1000; /* really nec ?*/
84 //printf("ts.tv_sec: %i\n", ts.tv_nsec);
89 //printf("vol = %i\n", vol);
96 static void client_cmd(const char *cmd
)
98 int ret
, status
, fds
[3] = {0, 0, 0};
100 char *cmdline
= make_message(BINDIR
"/para_client %s", cmd
);
102 PARA_NOTICE_LOG("%s\n", cmdline
);
103 ret
= para_exec_cmdline_pid(&pid
, cmdline
, fds
);
106 PARA_ERROR_LOG("%s\n", para_strerror(-ret
));
110 pid
= waitpid(pid
, &status
, 0);
111 while (pid
== -1 && errno
== EINTR
);
113 PARA_ERROR_LOG("%s\n", strerror(errno
));
116 if (!WIFEXITED(status
) || WEXITSTATUS(status
) != 0)
120 PARA_EMERG_LOG("command \"%s\" failed\n", cmd
);
124 static void change_afs_mode(char *afs_mode
)
131 cmd
= make_message("select %s", afs_mode
);
136 static int set_initial_volume(struct mixer
*m
, struct mixer_handle
*h
)
140 for (i
= 0; i
< conf
.ivol_given
; i
++) {
141 char *p
, *ch
, *arg
= para_strdup(conf
.ivol_arg
[i
]);
143 p
= strchr(arg
, ':');
152 ret
= para_atoi32(p
, &iv
);
157 ret
= set_channel(m
, h
, ch
);
161 PARA_WARNING_LOG("ignoring channel %s\n", ch
);
164 PARA_INFO_LOG("initial volume %s: %d\n", ch
, iv
);
174 static int sweet_dreams(struct mixer
*m
, struct mixer_handle
*h
)
176 time_t t1
, wake_time_epoch
;
179 int ret
, min
= conf
.wake_min_arg
;
180 char *fo_mood
= conf
.fo_mood_arg
;
181 char *fi_mood
= conf
.fi_mood_arg
;
182 char *sleep_mood
= conf
.sleep_mood_arg
;
183 int fit
= conf
.fi_time_arg
;
184 int fot
= conf
.fo_time_arg
;
185 int fiv
= conf
.fi_vol_arg
;
186 int fov
= conf
.fo_vol_arg
;
188 /* calculate wake time */
190 if (conf
.wake_hour_given
) {
191 int hour
= conf
.wake_hour_arg
;
193 if (tm
->tm_hour
> hour
|| (tm
->tm_hour
== hour
&& tm
->tm_min
> min
)) {
194 t1
+= 86400; /* wake time is tomorrow */
201 t1
+= 9 * 60 * 60; /* nine hours from now */
202 PARA_INFO_LOG("default wake time: %lu\n", (long unsigned)t1
);
205 wake_time_epoch
= mktime(tm
);
206 PARA_INFO_LOG("waketime: %u:%02u\n", tm
->tm_hour
, tm
->tm_min
);
210 ret
= set_initial_volume(m
, h
);
213 change_afs_mode(fo_mood
);
215 ret
= set_channel(m
, h
, conf
.mixer_channel_arg
);
218 ret
= fade(m
, h
, fov
, fot
);
222 ret
= m
->set(h
, fov
);
226 if (conf
.sleep_mood_given
) {
227 change_afs_mode(sleep_mood
);
233 change_afs_mode(fi_mood
);
236 if (wake_time_epoch
<= t1
+ fit
)
238 delay
= wake_time_epoch
- t1
- fit
;
239 PARA_INFO_LOG("sleeping %u seconds (%u:%02u)\n",
241 (delay
% 3600) / 60);
245 ret
= fade(m
, h
, fiv
, fit
);
246 PARA_INFO_LOG("fade complete, returning\n");
250 static int snooze(struct mixer
*m
, struct mixer_handle
*h
)
254 if (conf
.so_time_arg
<= 0)
260 if (val
< conf
.so_vol_arg
)
261 ret
= m
->set(h
, conf
.so_vol_arg
);
263 ret
= fade(m
, h
, conf
.so_vol_arg
, conf
.so_time_arg
);
267 PARA_NOTICE_LOG("%d seconds snooze time...\n", conf
.snooze_time_arg
);
268 sleep(conf
.snooze_time_arg
);
270 return fade(m
, h
, conf
.si_vol_arg
, conf
.si_time_arg
);
273 static int configfile_exists(void)
275 static char *config_file
;
277 if (!conf
.config_file_given
) {
278 char *home
= para_homedir();
280 config_file
= make_message("%s/.paraslash/fade.conf", home
);
282 conf
.config_file_arg
= config_file
;
284 return file_exists(conf
.config_file_arg
);
287 static void init_mixers(void)
292 struct mixer
*m
= &supported_mixer
[i
];
293 PARA_DEBUG_LOG("initializing mixer API #%d (%s)\n",
299 static int set_val(struct mixer
*m
, struct mixer_handle
*h
)
301 return m
->set(h
, conf
.val_arg
);
304 static struct mixer
*get_mixer_or_die(void)
308 if (!conf
.mixer_api_given
)
312 if (!strcmp(mixer_name
[i
], conf
.mixer_api_arg
))
314 if (i
< NUM_SUPPORTED_MIXERS
) {
315 PARA_NOTICE_LOG("using %s mixer API\n", mixer_name
[i
]);
316 return supported_mixer
+ i
;
318 printf("available mixer APIs: ");
320 int d
= (i
== DEFAULT_MIXER
);
321 printf("%s%s%s ", d
? "[" : "", mixer_name
[i
], d
? "]" : "");
327 __noreturn
static void print_help_and_die(void)
329 struct ggo_help h
= DEFINE_GGO_HELP(fade
);
330 bool d
= conf
.detailed_help_given
;
332 ggo_print_help(&h
, d
? GPH_STANDARD_FLAGS_DETAILED
: GPH_STANDARD_FLAGS
);
336 int main(int argc
, char *argv
[])
340 struct mixer_handle
*h
= NULL
;
342 fade_cmdline_parser(argc
, argv
, &conf
);
343 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
344 version_handle_flag("fade", conf
.version_given
);
345 if (conf
.help_given
|| conf
.detailed_help_given
)
346 print_help_and_die();
347 ret
= configfile_exists();
348 if (!ret
&& conf
.config_file_given
) {
349 PARA_EMERG_LOG("can not read config file %s\n",
350 conf
.config_file_arg
);
354 struct fade_cmdline_parser_params params
= {
358 .check_ambiguity
= 0,
361 fade_cmdline_parser_config_file(conf
.config_file_arg
,
363 loglevel
= get_loglevel_by_name(conf
.loglevel_arg
);
366 m
= get_mixer_or_die();
367 ret
= m
->open(conf
.mixer_device_arg
, &h
);
370 ret
= set_channel(m
, h
, conf
.mixer_channel_arg
);
371 if (ret
== -E_BAD_CHANNEL
) {
372 char *channels
= m
->get_channels(h
);
373 printf("Available channels: %s\n", channels
);
378 switch (conf
.mode_arg
) {
380 ret
= fade(m
, h
, conf
.fade_vol_arg
, conf
.fade_time_arg
);
382 case mode_arg_snooze
:
388 default: /* sleep mode */
389 ret
= sweet_dreams(m
, h
);
395 PARA_EMERG_LOG("%s\n", para_strerror(-ret
));
396 return ret
< 0? EXIT_FAILURE
: EXIT_SUCCESS
;