2 * This file is part of DisOrder.
3 * Copyright (C) 2004-2009 Richard Kettlewell
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 /** @file server/background.c
19 * @brief Background process support for playing tracks
22 #include "disorder-server.h"
24 /** @brief Fork the player or decoder for @p q
25 * @param player Pointer to player information
26 * @param q Track to play or decode
27 * @param child Function to run inside fork
28 * @param bgdata Passed to @c child()
30 * @c q->pl had better already be set.
32 int play_background(ev_source
*ev
,
33 const struct stringlist
*player
,
34 struct queue_entry
*q
,
35 play_background_child_fn
*child
,
38 struct pbgc_params params
[1];
40 memset(params
, 0, sizeof params
);
41 /* Get the raw path. This needs to be done outside the fork. It's needed by
42 * the play-track callback which has to have the raw filename bytes we got
43 * from readdir() as well as the normalized unicode version of the track
44 * name. (Emphasize 'normalized'; even if you use UTF-8 for your filenames,
45 * they might not be normalized and if they are they might not be normalized
46 * to the same canonical form as DisOrder uses.) */
47 params
->rawpath
= trackdb_rawpath(q
->track
);
48 /* Call the prefork function in the player module. None of the built-in
49 * modules use this so it's not well tested, unfortunately. */
50 if(q
->type
& DISORDER_PLAYER_PREFORK
)
51 if(!(q
->data
= play_prefork(q
->pl
, q
->track
))) {
52 error(0, "prefork function for %s failed", q
->track
);
53 return START_HARDFAIL
;
55 /* Capture the player/decoder's stderr and feed it into our logs.
57 * Use the second arg as the tag if available (it's probably a command name),
58 * otherwise the module name. */
60 lfd
= logfd(ev
, player
->s
[2] ? player
->s
[2] : player
->s
[1]);
63 /* Parse player arguments */
64 int optc
= player
->n
- 2;
65 const char **optv
= (const char **)&player
->s
[2];
66 while(optc
> 0 && optv
[0][0] == '-') {
67 if(!strcmp(optv
[0], "--")) {
72 if(!strcmp(optv
[0], "--wait-for-device")
73 || !strncmp(optv
[0], "--wait-for-device=", 18)) {
74 const char *waitdevice
;
75 if((waitdevice
= strchr(optv
[0], '='))) {
76 params
->waitdevice
= waitdevice
+ 1;
78 params
->waitdevice
= ""; /* use default */
82 error(0, "unknown option %s", optv
[0]);
83 return START_HARDFAIL
;
88 /* Create the child process */
89 switch(q
->pid
= fork()) {
91 /* Child of disorderd */
93 progname
= "disorderd-fork";
95 signal(SIGPIPE
, SIG_DFL
);
96 /* Send our log output to DisOrder's logs */
100 xclose(lfd
); /* tidy up */
102 /* Create a new process group, ID = child PID */
104 _exit(child(q
, params
, bgdata
));
106 /* Back in disorderd (child could not be created) */
107 error(errno
, "error calling fork");
108 if(q
->type
& DISORDER_PLAYER_PREFORK
)
109 play_cleanup(q
->pl
, q
->data
); /* else would leak */
112 return START_SOFTFAIL
;
114 /* We don't need the child's end of the log pipe */
117 /* Set the child's process group ID.
119 * But wait, didn't we already set it in the child? Yes, but it's possible
120 * that we'll need to address it by process group ID before it gets that far,
121 * so we set it here too. One or the other may fail but as long as one
122 * succeeds that's fine.
124 setpgid(q
->pid
, q
->pid
);
125 /* Ask the event loop to tell us when the child terminates */
126 D(("player subprocess ID %lu", (unsigned long)q
->pid
));