758 lines
19 KiB
C
758 lines
19 KiB
C
/**
|
|
* ecaplay.c: A simple command-line tool for playing audio files.
|
|
*
|
|
* Copyright (C) 1999-2002,2004-2006 Kai Vehmanen
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
*/
|
|
|
|
/**
|
|
* TODO:
|
|
* - show playlist length during runtime
|
|
* - random start switch (both for cmdline and playlist modes)
|
|
* - write some notes about locking issues
|
|
*/
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
#include <config.h>
|
|
#endif
|
|
|
|
#include <assert.h>
|
|
#include <limits.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h> /* ANSI-C: malloc(), free() */
|
|
#include <string.h> /* ANSI-C: strlen(), strncmp() */
|
|
|
|
#include <unistd.h> /* POSIX: ... */
|
|
#include <signal.h> /* POSIX: sigaction() */
|
|
#include <sys/stat.h> /* POSIX: mkdir() */
|
|
#include <sys/types.h> /* POSIX: mkdir() */
|
|
|
|
#include <ecasoundc.h>
|
|
|
|
/**
|
|
* Function declarations
|
|
*/
|
|
|
|
int main(int argc, char *argv[]);
|
|
|
|
static void add_input_to_chainsetup(eci_handle_t eci, const char* nextrack);
|
|
static int flush_tracks(void);
|
|
static const char* get_next_track(int *tracknum, int argc, char *argv[], eci_handle_t *eci);
|
|
static char* get_playlist_path(void);
|
|
static const char* get_track_cmdline(int n, int argc, char *argv[]);
|
|
static const char* get_track_playlist(int* next_track);
|
|
static void initialize_chainsetup_for_playback(eci_handle_t* eci, const char* nexttrack, int tracknum);
|
|
static void initialize_check_output(eci_handle_t* eci);
|
|
static int list_tracks(void);
|
|
static int play_tracks(int argc, char *argv[]);
|
|
static void print_usage(FILE* stream);
|
|
static int process_option(const char* option);
|
|
static int queue_tracks(int argc, char *argv[]);
|
|
static int set_audio_format(eci_handle_t* eci, const char* fmt);
|
|
static void setup_signal_handling(void);
|
|
static void signal_handler(int signum);
|
|
|
|
/**
|
|
* Definitions and options
|
|
*/
|
|
|
|
#define ECAPLAY_AFMT_MAXLEN 64
|
|
#define ECAPLAY_EIAM_LOGLEVEL 256
|
|
#define ECAPLAY_TIMEOUT 3
|
|
|
|
#define ECAPLAY_MODE_NORMAL 0
|
|
#define ECAPLAY_MODE_PL_FLUSH 1
|
|
#define ECAPLAY_MODE_PL_LIST 2
|
|
#define ECAPLAY_MODE_PL_PLAY 3
|
|
#define ECAPLAY_MODE_PL_QUEUE 4
|
|
|
|
#define ECAPLAY_PLAYLIST_BASEDIR ".ecasound"
|
|
#define ECAPLAY_PLAYLIST_FILE "ecaplay_queue"
|
|
|
|
/**
|
|
* Global variables
|
|
*/
|
|
|
|
static const char* ecaplay_version = "20061206-45"; /* ecaplay version */
|
|
static char ecaplay_next[PATH_MAX]; /* file to play next */
|
|
static char ecaplay_audio_format[ECAPLAY_AFMT_MAXLEN]; /* audio format to use */
|
|
static const char* ecaplay_output = NULL; /* output device to use */
|
|
static int ecaplay_debuglevel = ECAPLAY_EIAM_LOGLEVEL; /* debug level to use */
|
|
static int ecaplay_skip = 0; /* how many playlist items to skip */
|
|
static int ecaplay_mode = ECAPLAY_MODE_NORMAL; /* playlist mode */
|
|
/* FIX: static int ecaplay_list_len = -1; playlist length */
|
|
static int ecaplay_initialized = 0; /* playlist mode */
|
|
static sig_atomic_t ecaplay_skip_flag = 0; /* signal flag for ctrl-c */
|
|
|
|
/**
|
|
* Function definitions
|
|
*/
|
|
|
|
int main(int argc, char *argv[])
|
|
{
|
|
int i, res = 0;
|
|
|
|
/* get the default output device */
|
|
ecaplay_output = getenv("ECAPLAY_OUTPUT_DEVICE");
|
|
|
|
/* process command-line arguments */
|
|
for(i = 1; i < argc; i++) { res += process_option(argv[i]); }
|
|
|
|
if (res == 0) {
|
|
switch(ecaplay_mode) {
|
|
case ECAPLAY_MODE_PL_FLUSH:
|
|
res = flush_tracks();
|
|
break;
|
|
|
|
case ECAPLAY_MODE_PL_LIST:
|
|
res = list_tracks();
|
|
break;
|
|
|
|
case ECAPLAY_MODE_PL_QUEUE:
|
|
res = queue_tracks(argc, argv);
|
|
break;
|
|
|
|
case ECAPLAY_MODE_NORMAL:
|
|
case ECAPLAY_MODE_PL_PLAY:
|
|
res = play_tracks(argc, argv);
|
|
break;
|
|
|
|
default:
|
|
assert(0);
|
|
}
|
|
}
|
|
|
|
if (res != 0) {
|
|
fprintf(stderr, "(ecaplay) Errors encountered, return code is %d.\n", res);
|
|
}
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Adds input 'nexttrack' to currently selected chainsetup
|
|
* of 'eci'. Sets the global variable 'ecaplay_audio_format'.
|
|
*/
|
|
static void add_input_to_chainsetup(eci_handle_t eci, const char* nexttrack)
|
|
{
|
|
size_t len = strlen("ai-add '") + strlen(nexttrack) + strlen("'") + 1;
|
|
char* tmpbuf = malloc(len);
|
|
|
|
assert(tmpbuf != NULL);
|
|
snprintf(tmpbuf, len, "ai-add \"%s\"", nexttrack);
|
|
eci_command_r(eci, tmpbuf);
|
|
|
|
/* check that add succeeded */
|
|
eci_command_r(eci, "ai-list");
|
|
if (eci_last_string_list_count_r(eci) != 1) {
|
|
fprintf(stderr, "(ecaplay) Warning! Failed to add input '%s'.\n", nexttrack);
|
|
}
|
|
|
|
/* we must connect to get correct input format */
|
|
eci_command_r(eci, "ao-add null");
|
|
eci_command_r(eci, "cs-connect");
|
|
eci_command_r(eci, "ai-iselect 1");
|
|
eci_command_r(eci, "ai-get-format");
|
|
|
|
strncpy(ecaplay_audio_format,
|
|
eci_last_string_r(eci),
|
|
ECAPLAY_AFMT_MAXLEN);
|
|
ecaplay_audio_format[ECAPLAY_AFMT_MAXLEN - 1] = 0;
|
|
|
|
/* disconnect and remove the null output */
|
|
eci_command_r(eci, "cs-disconnect");
|
|
eci_command_r(eci, "ao-iselect 1");
|
|
eci_command_r(eci, "ao-remove");
|
|
|
|
free(tmpbuf);
|
|
}
|
|
|
|
/**
|
|
* Flushes the playlist contents.
|
|
*
|
|
* @return zero on success, non-zero otherwise
|
|
*/
|
|
static int flush_tracks(void)
|
|
{
|
|
char *path = get_playlist_path();
|
|
if (truncate(path, 0) != 0) {
|
|
printf("(ecaplay) Unable to flush playlist '%s'.\n", path);
|
|
return -1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/**
|
|
* Checks that current chainsetup has exactly one
|
|
* output.
|
|
*/
|
|
static void initialize_check_output(eci_handle_t* eci)
|
|
{
|
|
eci_command_r(eci, "ao-list");
|
|
if (eci_last_string_list_count_r(eci) != 1) {
|
|
fprintf(stderr, "(ecaplay) Warning! Failed to add output device.\n");
|
|
}
|
|
else {
|
|
static int once = 1;
|
|
if (once) {
|
|
eci_command_r(eci, "ao-iselect 1");
|
|
eci_command_r(eci, "ao-describe");
|
|
char *tmpstr = (char*)eci_last_string_r(eci);
|
|
/* skip the "-x:" prefix where x is one of [io] */
|
|
while(*tmpstr && *tmpstr++ != ':')
|
|
;
|
|
printf("(ecaplay) Output device: '%s'\n", tmpstr);
|
|
once = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void initialize_chainsetup_for_playback(eci_handle_t* eci, const char* nexttrack, int tracknum)
|
|
{
|
|
const char* ret = NULL;
|
|
|
|
*eci = eci_init_r();
|
|
ecaplay_initialized = 1;
|
|
|
|
if (ecaplay_debuglevel != -1) {
|
|
char tmpbuf[32];
|
|
snprintf(tmpbuf, 32, "debug %d", ecaplay_debuglevel);
|
|
eci_command_r(*eci, tmpbuf);
|
|
}
|
|
|
|
eci_command_r(*eci, "cs-add ecaplay_chainsetup");
|
|
/* check that add succeeded */
|
|
eci_command_r(*eci, "cs-list");
|
|
if (eci_last_string_list_count_r(*eci) != 2) {
|
|
fprintf(stderr, "(ecaplay) Warning! Failed to add a new chainsetup.\n");
|
|
}
|
|
|
|
/* as this is a new chainsetup, we can assume that
|
|
* adding chains succeeds */
|
|
eci_command_r(*eci, "c-add ecaplay_chain");
|
|
|
|
add_input_to_chainsetup(*eci, nexttrack);
|
|
set_audio_format(*eci, ecaplay_audio_format);
|
|
|
|
if (ecaplay_output == NULL) {
|
|
eci_command_r(*eci, "ao-add-default");
|
|
|
|
/* check that add succeeded */
|
|
initialize_check_output(*eci);
|
|
}
|
|
else {
|
|
int len = strlen("ao-add ") + strlen(ecaplay_output) + 1;
|
|
char* tmpbuf = (char*)malloc(len);
|
|
snprintf(tmpbuf, len, "ao-add %s", ecaplay_output);
|
|
eci_command_r(*eci, tmpbuf);
|
|
initialize_check_output(*eci);
|
|
free(tmpbuf);
|
|
}
|
|
|
|
/* FIXME: add detection of consecutive errors */
|
|
|
|
eci_command_r(*eci, "cs-connect");
|
|
if (eci_error_r(*eci)) {
|
|
fprintf(stderr, "(ecaplay) Unable to play file '%s':\n%s\n", nexttrack, eci_last_error_r(*eci));
|
|
}
|
|
else {
|
|
eci_command_r(*eci, "cs-connected");
|
|
ret = eci_last_string_r(*eci);
|
|
if (strncmp(ret, "ecaplay_chainsetup", strlen("ecaplay_chainsetup")) != 0) {
|
|
fprintf(stderr, "(ecaplay) Error while playing file '%s' . Skipping...\n", nexttrack);
|
|
}
|
|
else {
|
|
/* note: audio format set separately for each input file */
|
|
printf("(ecaplay) Playing %d: '%s' (%s).\n", tracknum, nexttrack, ecaplay_audio_format);
|
|
eci_command_r(*eci, "start");
|
|
}
|
|
}
|
|
}
|
|
|
|
static const char* get_next_track(int *tracknum, int argc, char *argv[], eci_handle_t *eci)
|
|
{
|
|
const char *nexttrack = NULL;
|
|
|
|
if (ecaplay_mode == ECAPLAY_MODE_PL_PLAY)
|
|
nexttrack = get_track_playlist(tracknum);
|
|
else
|
|
nexttrack = get_track_cmdline(*tracknum, argc, argv);
|
|
|
|
if (nexttrack != NULL) {
|
|
/* queue nexttrack for playing */
|
|
if (ecaplay_initialized) {
|
|
eci_cleanup_r(*eci);
|
|
}
|
|
initialize_chainsetup_for_playback(eci, nexttrack, *tracknum);
|
|
}
|
|
else {
|
|
/* reached end of playlist */
|
|
if (ecaplay_mode != ECAPLAY_MODE_PL_PLAY) {
|
|
/* normal mode; end processing after all files played */
|
|
/* printf("(ecaplay) No more files...\n"); */
|
|
assert(nexttrack == NULL);
|
|
}
|
|
else {
|
|
/* if in playlist mode, loop from beginning */
|
|
*tracknum = 1;
|
|
|
|
/* FIXME: if in playlist mode; query the current lenght of
|
|
* playlist and set 'tracknum = (tracknum % pllen)' */
|
|
|
|
if (ecaplay_mode == ECAPLAY_MODE_PL_PLAY)
|
|
nexttrack = get_track_playlist(tracknum);
|
|
else
|
|
nexttrack = get_track_cmdline(*tracknum, argc, argv);
|
|
|
|
/* printf("(ecaplay) Looping back to start of playlist...(%s)\n", nexttrack); */
|
|
|
|
if (nexttrack != NULL) {
|
|
/* queue nexttrack for playing */
|
|
if (ecaplay_initialized) {
|
|
eci_cleanup_r(*eci);
|
|
}
|
|
initialize_chainsetup_for_playback(eci, nexttrack, *tracknum);
|
|
}
|
|
else {
|
|
/* get_next_track() failed two times, stopping processing */
|
|
assert(nexttrack == NULL);
|
|
}
|
|
}
|
|
}
|
|
|
|
return nexttrack;
|
|
}
|
|
|
|
/**
|
|
* Returns the track number 'n' from the list
|
|
* given in argc and argv.
|
|
*
|
|
* @return track name or NULL on error
|
|
*/
|
|
static const char* get_track_cmdline(int n, int argc, char *argv[])
|
|
{
|
|
int i, c = 0;
|
|
|
|
assert(n > 0 && n <= argc);
|
|
|
|
for(i = 1; i < argc; i++) {
|
|
/* FIXME: add support for '-- -foo.wav' */
|
|
if (argv[i][0] != '-') {
|
|
if (++c == n) {
|
|
return argv[i];
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
/**
|
|
* Returns a string containing the full path to the
|
|
* playlist file. Ownership of the string is transfered
|
|
* to the caller (i.e. it must be free()'ed).
|
|
*
|
|
* @return full pathname or NULL if error has occured
|
|
*/
|
|
static char* get_playlist_path(void)
|
|
{
|
|
char *path = malloc(PATH_MAX);
|
|
struct stat statbuf;
|
|
|
|
/* create pathname based on HOME */
|
|
strncpy(path, getenv("HOME"), PATH_MAX);
|
|
strncat(path, "/" ECAPLAY_PLAYLIST_BASEDIR, PATH_MAX - strlen(path) - 1);
|
|
|
|
/* make sure basedir exists */
|
|
if (stat(path, &statbuf) != 0) {
|
|
printf("(ecaplay) Creating directory %s.\n", path);
|
|
mkdir(path, 0700);
|
|
}
|
|
else {
|
|
if (!S_ISDIR(statbuf.st_mode)) {
|
|
/* error, basedir exists but is not a directory */
|
|
free(path);
|
|
path = NULL;
|
|
}
|
|
}
|
|
|
|
if (path != NULL) {
|
|
/* add filename to basedir */
|
|
strncat(path, "/" ECAPLAY_PLAYLIST_FILE, PATH_MAX - strlen(path) - 1);
|
|
}
|
|
|
|
return path;
|
|
}
|
|
|
|
/**
|
|
* Returns the track from playlist matching number 'next_track'.
|
|
*
|
|
* In case 'next_track' is larger than the playlist length,
|
|
* track 'next_track mod playlist_len' will be selected, and
|
|
* the modified playlist item number stored to 'next_track'.
|
|
*
|
|
* Note: modifies global variable 'ecaplay_next'.
|
|
*
|
|
* @return track name or NULL on error
|
|
*/
|
|
static const char* get_track_playlist(int* next_track)
|
|
{
|
|
|
|
const char *res = NULL;
|
|
char *path;
|
|
FILE *f1;
|
|
int next = *next_track;
|
|
|
|
assert(next > 0);
|
|
|
|
path = get_playlist_path();
|
|
if (path == NULL) {
|
|
return path;
|
|
}
|
|
|
|
f1 = fopen(path, "rb");
|
|
if (f1 != NULL) {
|
|
int c, w, cur_item = 1;
|
|
|
|
/* iterate through all data octet at a time */
|
|
for(w = 0;;) {
|
|
c = fgetc(f1);
|
|
if (c == EOF) {
|
|
if (next > cur_item) {
|
|
/* next_track beyond playlist length, reset to valid track number */
|
|
next = next % cur_item;
|
|
*next_track = next;
|
|
/* seek back to start and look again */
|
|
fseek(f1, 0, SEEK_SET);
|
|
cur_item = 1;
|
|
w = 0;
|
|
continue;
|
|
}
|
|
break;
|
|
}
|
|
|
|
if (cur_item == next) {
|
|
if (c == '\n') {
|
|
ecaplay_next[w] = 0;
|
|
res = ecaplay_next;
|
|
break;
|
|
}
|
|
else {
|
|
ecaplay_next[w] = c;
|
|
}
|
|
++w;
|
|
}
|
|
if (c == '\n') {
|
|
++cur_item;
|
|
}
|
|
}
|
|
|
|
/* close the file and return results */
|
|
fclose(f1);
|
|
}
|
|
|
|
free(path);
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Lists tracks on the playlist.
|
|
*
|
|
* @return zero on success, non-zero otherwise
|
|
*/
|
|
static int list_tracks(void)
|
|
{
|
|
FILE *f1;
|
|
char *path = get_playlist_path();
|
|
|
|
f1 = fopen(path, "rb");
|
|
if (f1 != NULL) {
|
|
int c;
|
|
while((c = fgetc(f1)) != EOF) {
|
|
printf("%c", c);
|
|
}
|
|
fclose(f1);
|
|
return 0;
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
/**
|
|
* Play tracks using the Ecasound engine via the
|
|
* ECI interface.
|
|
*
|
|
* Depending on the mode, tracks are selected either
|
|
* from the command-line or from the playlist.
|
|
*/
|
|
static int play_tracks(int argc, char *argv[])
|
|
{
|
|
eci_handle_t eci = NULL;
|
|
int tracknum = 1, stop = 0;
|
|
const char* nexttrack = NULL;
|
|
|
|
assert(ecaplay_mode == ECAPLAY_MODE_NORMAL ||
|
|
ecaplay_mode == ECAPLAY_MODE_PL_PLAY);
|
|
|
|
tracknum += ecaplay_skip;
|
|
|
|
nexttrack = get_next_track(&tracknum, argc, argv, &eci);
|
|
|
|
if (nexttrack != NULL) {
|
|
setup_signal_handling();
|
|
|
|
while(nexttrack != NULL) {
|
|
unsigned int timeleft = ECAPLAY_TIMEOUT;
|
|
|
|
while(timeleft > 0) {
|
|
timeleft = sleep(timeleft);
|
|
|
|
if (timeleft > 0 && ecaplay_skip_flag > 1) {
|
|
fprintf(stderr, "\n(ecaplay) Interrupted, exiting...\n");
|
|
eci_cleanup_r(eci);
|
|
stop = 1;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* see above while() loop */
|
|
if (stop) break;
|
|
|
|
if (ecaplay_skip_flag == 0) {
|
|
eci_command_r(eci, "engine-status");
|
|
}
|
|
else {
|
|
printf("(ecaplay) Skipping...\n");
|
|
}
|
|
|
|
if (ecaplay_skip_flag != 0 || strcmp(eci_last_string_r(eci), "running") != 0) {
|
|
ecaplay_skip_flag = 0;
|
|
++tracknum;
|
|
nexttrack = get_next_track(&tracknum, argc, argv, &eci);
|
|
/* printf("Next track is %s.\n", nexttrack); */
|
|
}
|
|
}
|
|
|
|
fprintf(stderr, "exiting...\n");
|
|
|
|
/* see while() loop above */
|
|
if (stop == 0) {
|
|
eci_cleanup_r(eci);
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static void print_usage(FILE* stream)
|
|
{
|
|
fprintf(stream, "Ecaplay v%s (%s)\n\n", ecaplay_version, VERSION);
|
|
|
|
fprintf(stream, "Copyright (C) 1997-2005 Kai Vehmanen, released under GPL licence \n");
|
|
fprintf(stream, "Ecaplay comes with ABSOLUTELY NO WARRANTY.\n");
|
|
fprintf(stream, "You may redistribute copies of ecasound under the terms of the GNU\n");
|
|
fprintf(stream, "General Public License. For more information about these matters, see\n");
|
|
fprintf(stream, "the file named COPYING.\n");
|
|
|
|
fprintf(stream, "\nUSAGE: ecaplay [-dfhklopq] [ file1 file2 ... fileN ]\n\n");
|
|
|
|
fprintf(stream, "See ecaplay(1) man page for more details.\n");
|
|
}
|
|
|
|
static int process_option(const char* option)
|
|
{
|
|
if (option[0] == '-') {
|
|
if (strncmp("--help", option, sizeof("--help")) == 0 ||
|
|
strncmp("--version", option, sizeof("--version")) == 0) {
|
|
print_usage(stdout);
|
|
return 0;
|
|
}
|
|
|
|
switch(option[1])
|
|
{
|
|
case 'd':
|
|
{
|
|
const char* level = &option[3];
|
|
if (option[2] != 0 && option[3] != 0) {
|
|
ecaplay_debuglevel |= atoi(level);
|
|
printf("(ecaplay) Setting log level to %d.\n", ecaplay_debuglevel);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'f':
|
|
{
|
|
ecaplay_mode = ECAPLAY_MODE_PL_FLUSH;
|
|
printf("(ecaplay) Flushing playlist.\n");
|
|
break;
|
|
}
|
|
|
|
case 'h':
|
|
{
|
|
print_usage(stdout);
|
|
return 0;
|
|
}
|
|
|
|
case 'k':
|
|
{
|
|
const char* skip = &option[3];
|
|
if (option[2] != 0 && option[3] != 0) {
|
|
ecaplay_skip = atoi(skip);
|
|
printf("(ecaplay) Skipping the first %d files..\n", ecaplay_skip);
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'l':
|
|
{
|
|
ecaplay_mode = ECAPLAY_MODE_PL_LIST;
|
|
/* printf("(ecaplay) Listing playlist contents.\n"); */
|
|
break;
|
|
}
|
|
|
|
case 'o':
|
|
{
|
|
const char* output = &option[3];
|
|
if (option[2] != 0 && option[3] != 0) {
|
|
ecaplay_output = output;
|
|
/* printf("(ecaplay) Output device: '%s'\n", ecaplay_output); */
|
|
}
|
|
break;
|
|
}
|
|
|
|
case 'p':
|
|
{
|
|
ecaplay_mode = ECAPLAY_MODE_PL_PLAY;
|
|
printf("(ecaplay) Playlist mode selected (file: %s).\n",
|
|
"~/" ECAPLAY_PLAYLIST_BASEDIR "/" ECAPLAY_PLAYLIST_FILE);
|
|
break;
|
|
}
|
|
|
|
case 'q':
|
|
{
|
|
ecaplay_mode = ECAPLAY_MODE_PL_QUEUE;
|
|
printf("(ecaplay) Queuing tracks to playlist.\n");
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
fprintf(stderr, "(ecaplay) Error! Unknown option '%s'.\n", option);
|
|
print_usage(stderr);
|
|
return 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int queue_tracks(int argc, char *argv[])
|
|
{
|
|
int i, res = 0;
|
|
char *path;
|
|
FILE *f1;
|
|
|
|
path = get_playlist_path();
|
|
/* path maybe NULL but fopen can handle it */
|
|
|
|
f1 = fopen(path, "a+b");
|
|
if (f1 != NULL) {
|
|
for(i = 1; i < argc; i++) {
|
|
char c = argv[i][0];
|
|
/* printf("(ecaplay) processing arg '%s' (%c).\n", argv[i], c); */
|
|
/* FIXME: add support for '-- -foo.wav' */
|
|
if (c != '-') {
|
|
/* printf("(ecaplay) 2:processing arg '%s' (%c).\n", argv[i], c); */
|
|
if (c != '/') {
|
|
/* reserve extra room for '/' */
|
|
char* tmp = malloc(PATH_MAX + strlen(argv[i]) + 1);
|
|
if (getcwd(tmp, PATH_MAX) != NULL) {
|
|
strcat(tmp, "/");
|
|
strcat(tmp, argv[i]);
|
|
printf("(ecaplay) Track '%s' added to playlist.\n", argv[i]);
|
|
fwrite(tmp, 1, strlen(tmp), f1);
|
|
}
|
|
free(tmp);
|
|
}
|
|
else {
|
|
printf("(ecaplay) Track '%s' added to playlist.\n", argv[i]);
|
|
fwrite(argv[i], 1, strlen(argv[i]), f1);
|
|
}
|
|
fwrite("\n", 1, 1, f1);
|
|
}
|
|
}
|
|
fclose(f1);
|
|
}
|
|
else {
|
|
res = -1;
|
|
}
|
|
|
|
free(path); /* can be NULL */
|
|
|
|
return res;
|
|
}
|
|
|
|
/**
|
|
* Sets the chainsetup audio format to 'fmt'.
|
|
*
|
|
* @return zero on success, non-zero on error
|
|
*/
|
|
int set_audio_format(eci_handle_t* eci, const char* fmt)
|
|
{
|
|
size_t len = strlen("cs-set-audio-format -f:") + strlen(fmt) + 1;
|
|
char* tmpbuf = malloc(len);
|
|
int res = 0;
|
|
|
|
strcpy(tmpbuf, "cs-set-audio-format ");
|
|
strcat(tmpbuf, fmt);
|
|
tmpbuf[len - 1] = 0;
|
|
eci_command_r(eci, tmpbuf);
|
|
if (eci_error_r(eci)) {
|
|
fprintf(stderr, "(ecaplay) Unknown audio format encountered.\n");
|
|
res = -1;
|
|
}
|
|
free(tmpbuf);
|
|
|
|
return res;
|
|
}
|
|
|
|
static void setup_signal_handling(void)
|
|
{
|
|
struct sigaction es_handler_int;
|
|
struct sigaction ign_handler;
|
|
|
|
es_handler_int.sa_handler = signal_handler;
|
|
sigemptyset(&es_handler_int.sa_mask);
|
|
es_handler_int.sa_flags = 0;
|
|
|
|
ign_handler.sa_handler = SIG_IGN;
|
|
sigemptyset(&ign_handler.sa_mask);
|
|
ign_handler.sa_flags = 0;
|
|
|
|
/* handle the follwing signals explicitly */
|
|
sigaction(SIGINT, &es_handler_int, 0);
|
|
|
|
/* ignore the following signals */
|
|
sigaction(SIGPIPE, &ign_handler, 0);
|
|
sigaction(SIGFPE, &ign_handler, 0);
|
|
}
|
|
|
|
static void signal_handler(int signum)
|
|
{
|
|
++ecaplay_skip_flag;
|
|
}
|