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