/
music_cmd.c
278 lines (240 loc) · 6.29 KB
1
/*
2
SDL_mixer: An audio mixer library based on the SDL library
3
Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
4
5
6
7
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
8
9
10
11
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
12
13
14
15
16
17
18
19
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
20
*/
21
#include "SDL_config.h"
22
23
24
/* This file supports an external command for playing music */
25
#ifdef MUSIC_CMD
26
27
28
29
30
31
32
33
#include <sys/types.h>
#include <sys/wait.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <signal.h>
34
#include <ctype.h>
35
36
37
38
#include <limits.h>
#if defined(__linux__) && defined(__arm__)
# include <linux/limits.h>
#endif
39
40
41
#include "music_cmd.h"
42
43
44
45
46
47
typedef struct {
char *file;
pid_t pid;
} MusicCMD;
48
49
/* Load a music stream from the given file */
50
static void *MusicCMD_CreateFromFile(const char *file)
51
{
52
53
54
MusicCMD *music;
/* Allocate and fill the music structure */
55
56
music = (MusicCMD *)SDL_calloc(1, sizeof *music);
if (music == NULL) {
57
Mix_SetError("Out of memory");
58
return NULL;
59
60
61
62
63
}
music->file = SDL_strdup(file);
music->pid = 0;
/* We're done */
64
return music;
65
66
67
68
69
}
/* Parse a command line buffer into arguments */
static int ParseCommandLine(char *cmdline, char **argv)
{
70
71
72
73
char *bufp;
int argc;
argc = 0;
74
for (bufp = cmdline; *bufp;) {
75
/* Skip leading whitespace */
76
while (isspace(*bufp)) {
77
78
79
++bufp;
}
/* Skip over argument */
80
if (*bufp == '"') {
81
++bufp;
82
83
if (*bufp) {
if (argv) {
84
85
86
87
88
argv[argc] = bufp;
}
++argc;
}
/* Skip over word */
89
while (*bufp && (*bufp != '"')) {
90
91
92
++bufp;
}
} else {
93
94
if (*bufp) {
if (argv) {
95
96
97
98
99
argv[argc] = bufp;
}
++argc;
}
/* Skip over word */
100
while (*bufp && ! isspace(*bufp)) {
101
102
103
++bufp;
}
}
104
105
if (*bufp) {
if (argv) {
106
107
108
109
110
*bufp = '\0';
}
++bufp;
}
}
111
if (argv) {
112
113
114
argv[argc] = NULL;
}
return(argc);
115
116
117
118
}
static char **parse_args(char *command, char *last_arg)
{
119
120
121
122
123
int argc;
char **argv;
/* Parse the command line */
argc = ParseCommandLine(command, NULL);
124
if (last_arg) {
125
126
127
++argc;
}
argv = (char **)SDL_malloc((argc+1)*(sizeof *argv));
128
if (argv == NULL) {
129
130
131
132
133
return(NULL);
}
argc = ParseCommandLine(command, argv);
/* Add last command line argument */
134
if (last_arg) {
135
136
137
138
139
140
argv[argc++] = last_arg;
}
argv[argc] = NULL;
/* We're ready! */
return(argv);
141
142
143
}
/* Start playback of a given music stream */
144
static int MusicCMD_Play(void *context)
145
{
146
147
148
149
150
151
152
MusicCMD *music = (MusicCMD *)context;
if (!music_cmd) {
Mix_SetError("You must call Mix_SetMusicCMD() first");
return -1;
}
153
#ifdef HAVE_FORK
154
music->pid = fork();
155
#else
156
music->pid = vfork();
157
#endif
158
switch(music->pid) {
159
160
/* Failed fork() system call */
case -1:
161
Mix_SetError("fork() failed");
162
return -1;
163
164
165
166
/* Child process - executes here */
case 0: {
char **argv;
167
168
169
170
171
172
/* Unblock signals in case we're called from a thread */
{
sigset_t mask;
sigemptyset(&mask);
sigprocmask(SIG_SETMASK, &mask, NULL);
173
174
}
175
176
177
178
179
180
181
182
183
184
185
186
187
188
/* Execute the command */
argv = parse_args(music_cmd, music->file);
if (argv != NULL) {
execvp(argv[0], argv);
/* exec() failed */
perror(argv[0]);
}
_exit(-1);
}
break;
/* Parent process - executes here */
default:
189
190
break;
}
191
return 0;
192
193
}
194
195
/* Return non-zero if a stream is currently playing */
static SDL_bool MusicCMD_IsPlaying(void *context)
196
{
197
MusicCMD *music = (MusicCMD *)context;
198
199
int status;
200
201
202
203
if (music->pid > 0) {
waitpid(music->pid, &status, WNOHANG);
if (kill(music->pid, 0) == 0) {
return SDL_TRUE;
204
205
}
}
206
return SDL_FALSE;
207
208
209
}
/* Pause playback of a given music stream */
210
static void MusicCMD_Pause(void *context)
211
{
212
213
MusicCMD *music = (MusicCMD *)context;
if (music->pid > 0) {
214
215
kill(music->pid, SIGSTOP);
}
216
217
218
}
/* Resume playback of a given music stream */
219
static void MusicCMD_Resume(void *context)
220
{
221
222
MusicCMD *music = (MusicCMD *)context;
if (music->pid > 0) {
223
224
kill(music->pid, SIGCONT);
}
225
226
}
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
/* Stop playback of a stream previously started with MusicCMD_Start() */
static void MusicCMD_Stop(void *context)
{
MusicCMD *music = (MusicCMD *)context;
int status;
if (music->pid > 0) {
while (kill(music->pid, 0) == 0) {
kill(music->pid, SIGTERM);
sleep(1);
waitpid(music->pid, &status, WNOHANG);
}
music->pid = 0;
}
}
243
/* Close the given music stream */
244
void MusicCMD_Delete(void *context)
245
{
246
MusicCMD *music = (MusicCMD *)context;
247
248
SDL_free(music->file);
SDL_free(music);
249
250
}
251
Mix_MusicInterface Mix_MusicInterface_CMD =
252
{
253
254
255
256
257
"CMD",
MIX_MUSIC_CMD,
MUS_CMD,
SDL_FALSE,
SDL_FALSE,
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
NULL, /* Load */
NULL, /* Open */
NULL, /* CreateFromRW */
MusicCMD_CreateFromFile,
NULL, /* SetVolume */
MusicCMD_Play,
MusicCMD_IsPlaying,
NULL, /* GetAudio */
NULL, /* Seek */
MusicCMD_Pause,
MusicCMD_Resume,
MusicCMD_Stop,
MusicCMD_Delete,
NULL, /* Close */
NULL, /* Unload */
};
#endif /* MUSIC_CMD */
277
278
/* vi: set ts=4 sw=4 expandtab: */