|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
mpg123: main code of the program (not of the decoder...)
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
copyright 1995-2013 by the mpg123 project - free software under the terms of the LGPL 2.1
|
|
Packit |
c32a2d |
see COPYING and AUTHORS files in distribution or http://mpg123.org
|
|
Packit |
c32a2d |
initially written by Michael Hipp
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#define ME "main"
|
|
Packit |
c32a2d |
#include "mpg123app.h"
|
|
Packit |
c32a2d |
#include "mpg123.h"
|
|
Packit |
c32a2d |
#include "out123.h"
|
|
Packit |
c32a2d |
#include "local.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_SYS_WAIT_H
|
|
Packit |
c32a2d |
#include <sys/wait.h>
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_SYS_RESOURCE_H
|
|
Packit |
c32a2d |
#include <sys/resource.h>
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include <errno.h>
|
|
Packit |
c32a2d |
#include <string.h>
|
|
Packit |
c32a2d |
#include <time.h>
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_SCHED_H
|
|
Packit |
c32a2d |
#include <sched.h>
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* be paranoid about setpriority support */
|
|
Packit |
c32a2d |
#ifndef PRIO_PROCESS
|
|
Packit |
c32a2d |
#undef HAVE_SETPRIORITY
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "common.h"
|
|
Packit |
c32a2d |
#include "sysutil.h"
|
|
Packit |
c32a2d |
#include "getlopt.h"
|
|
Packit |
c32a2d |
#include "term.h"
|
|
Packit |
c32a2d |
#include "playlist.h"
|
|
Packit |
c32a2d |
#include "httpget.h"
|
|
Packit |
c32a2d |
#include "metaprint.h"
|
|
Packit |
c32a2d |
#include "httpget.h"
|
|
Packit |
c32a2d |
#include "streamdump.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#include "debug.h"
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void usage(int err);
|
|
Packit |
c32a2d |
static void want_usage(char* arg);
|
|
Packit |
c32a2d |
static void long_usage(int err);
|
|
Packit |
c32a2d |
static void want_long_usage(char* arg);
|
|
Packit |
c32a2d |
static void print_title(FILE* o);
|
|
Packit |
c32a2d |
static void give_version(char* arg);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
struct parameter param = {
|
|
Packit |
c32a2d |
FALSE , /* aggressiv */
|
|
Packit |
c32a2d |
FALSE , /* shuffle */
|
|
Packit |
c32a2d |
FALSE , /* remote */
|
|
Packit |
c32a2d |
FALSE , /* remote to stderr */
|
|
Packit |
c32a2d |
FALSE , /* silent operation */
|
|
Packit |
c32a2d |
FALSE , /* xterm title on/off */
|
|
Packit |
c32a2d |
0 , /* second level buffer size */
|
|
Packit |
c32a2d |
0 , /* verbose level */
|
|
Packit |
c32a2d |
DEFAULT_OUTPUT_MODULE, /* output module */
|
|
Packit |
c32a2d |
NULL, /* output device */
|
|
Packit |
c32a2d |
0, /* destination (headphones, ...) */
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
FALSE, /* term control */
|
|
Packit |
c32a2d |
TRUE, /* term visuals */
|
|
Packit |
c32a2d |
MPG123_TERM_USR1,
|
|
Packit |
c32a2d |
MPG123_TERM_USR2,
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
FALSE , /* checkrange */
|
|
Packit |
c32a2d |
0 , /* force_reopen, always (re)opens audio device for next song */
|
|
Packit |
c32a2d |
/* test_cpu flag is valid for multi and 3dnow.. even if 3dnow is built alone; ensure it appears only once */
|
|
Packit |
c32a2d |
FALSE , /* normal operation */
|
|
Packit |
c32a2d |
FALSE, /* try to run process in 'realtime mode' */
|
|
Packit |
c32a2d |
#ifdef HAVE_WINDOWS_H
|
|
Packit |
c32a2d |
0, /* win32 process priority */
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
0, /* default is to play all titles in playlist */
|
|
Packit |
c32a2d |
NULL, /* no playlist per default */
|
|
Packit |
c32a2d |
0 /* condensed id3 per default */
|
|
Packit |
c32a2d |
,0 /* list_cpu */
|
|
Packit |
c32a2d |
,NULL /* cpu */
|
|
Packit |
c32a2d |
#ifdef FIFO
|
|
Packit |
c32a2d |
,NULL
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
,0 /* timeout */
|
|
Packit |
c32a2d |
,1 /* loop */
|
|
Packit |
c32a2d |
,0 /* delay */
|
|
Packit |
c32a2d |
,0 /* index */
|
|
Packit |
c32a2d |
/* Parameters for mpg123 handle, defaults are queried from library! */
|
|
Packit |
c32a2d |
,0 /* down_sample */
|
|
Packit |
c32a2d |
,0 /* rva */
|
|
Packit |
c32a2d |
,0 /* halfspeed */
|
|
Packit |
c32a2d |
,0 /* doublespeed */
|
|
Packit |
c32a2d |
,0 /* start_frame */
|
|
Packit |
c32a2d |
,-1 /* frame_number */
|
|
Packit |
c32a2d |
,0 /* outscale */
|
|
Packit |
c32a2d |
,0 /* flags */
|
|
Packit |
c32a2d |
,0 /* force_rate */
|
|
Packit |
c32a2d |
,1 /* ICY */
|
|
Packit |
c32a2d |
,1024 /* resync_limit */
|
|
Packit |
c32a2d |
,0 /* smooth */
|
|
Packit |
c32a2d |
,0.0 /* pitch */
|
|
Packit |
c32a2d |
,0 /* appflags */
|
|
Packit |
c32a2d |
,NULL /* proxyurl */
|
|
Packit |
c32a2d |
,0 /* keep_open */
|
|
Packit |
c32a2d |
,0 /* force_utf8 */
|
|
Packit |
c32a2d |
,INDEX_SIZE
|
|
Packit |
c32a2d |
,NULL /* force_encoding */
|
|
Packit |
c32a2d |
,0.2 /* preload */
|
|
Packit |
c32a2d |
,-1 /* preframes */
|
|
Packit |
c32a2d |
,-1 /* gain */
|
|
Packit |
c32a2d |
,NULL /* stream dump file */
|
|
Packit |
c32a2d |
,0 /* ICY interval */
|
|
Packit |
c32a2d |
,"mpg123" /* name */
|
|
Packit |
c32a2d |
,0. /* device buffer */
|
|
Packit |
c32a2d |
};
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123_handle *mh = NULL;
|
|
Packit |
c32a2d |
off_t framenum;
|
|
Packit |
c32a2d |
off_t frames_left;
|
|
Packit |
c32a2d |
out123_handle *ao = NULL;
|
|
Packit |
c32a2d |
static long output_propflags = 0;
|
|
Packit |
c32a2d |
char *prgName = NULL;
|
|
Packit |
c32a2d |
/* ThOr: pointers are not TRUE or FALSE */
|
|
Packit |
c32a2d |
char *equalfile = NULL;
|
|
Packit |
c32a2d |
struct httpdata htd;
|
|
Packit |
c32a2d |
int fresh = TRUE;
|
|
Packit |
c32a2d |
FILE* aux_out = NULL; /* Output for interesting information, normally on stdout to be parseable. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int intflag = FALSE;
|
|
Packit |
c32a2d |
int deathflag = FALSE;
|
|
Packit |
c32a2d |
static int skip_tracks = 0;
|
|
Packit |
c32a2d |
int OutputDescriptor;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int filept = -1;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int network_sockets_used = 0; /* Win32 socket open/close Support */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
char *fullprogname = NULL; /* Copy of argv[0]. */
|
|
Packit |
c32a2d |
char *binpath; /* Path to myself. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* File-global storage of command line arguments.
|
|
Packit |
c32a2d |
They may be needed for cleanup after charset conversion. */
|
|
Packit |
c32a2d |
static char **argv = NULL;
|
|
Packit |
c32a2d |
static int argc = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Cleanup marker to know that we intiialized libmpg123 already. */
|
|
Packit |
c32a2d |
static int cleanup_mpg123 = FALSE;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static long new_header = FALSE;
|
|
Packit |
c32a2d |
static char *prebuffer = NULL;
|
|
Packit |
c32a2d |
static size_t prebuffer_size = 0;
|
|
Packit |
c32a2d |
static size_t prebuffer_fill = 0;
|
|
Packit |
c32a2d |
static size_t minbytes = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void set_intflag()
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("set_intflag TRUE");
|
|
Packit |
c32a2d |
intflag = TRUE;
|
|
Packit |
c32a2d |
skip_tracks = 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
static void catch_interrupt(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
intflag = TRUE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
static void handle_fatal_msg(const char *msg, size_t n)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(msg && !param.quiet)
|
|
Packit |
c32a2d |
write(STDERR_FILENO, msg, n);
|
|
Packit |
c32a2d |
intflag = TRUE;
|
|
Packit |
c32a2d |
deathflag = TRUE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
static void catch_fatal_term(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const char msg[] = "\nmpg123: death by SIGTERM\n";
|
|
Packit |
c32a2d |
handle_fatal_msg(msg, sizeof(msg));
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
static void catch_fatal_pipe(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* If the SIGPIPE is because of piped stderr, trying to write
|
|
Packit |
c32a2d |
in the signal handler hangs the program. */
|
|
Packit |
c32a2d |
handle_fatal_msg(NULL, 0);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void skip_track(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
intflag = TRUE;
|
|
Packit |
c32a2d |
++skip_tracks;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void next_track(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
playlist_jump(+1);
|
|
Packit |
c32a2d |
skip_track();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void prev_track(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
playlist_jump(-1);
|
|
Packit |
c32a2d |
skip_track();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void next_dir(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
playlist_next_dir();
|
|
Packit |
c32a2d |
skip_track();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void prev_dir(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
playlist_prev_dir();
|
|
Packit |
c32a2d |
skip_track();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void safe_exit(int code);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void play_prebuffer(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Ensure that the prebuffer bit has been posted. */
|
|
Packit |
c32a2d |
if(prebuffer_fill)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(out123_play(ao, prebuffer, prebuffer_fill) < prebuffer_fill)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("Deep trouble! Cannot flush to my output anymore!");
|
|
Packit |
c32a2d |
safe_exit(133);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
prebuffer_fill = 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Drain output device/buffer, but still give the option to interrupt things. */
|
|
Packit |
c32a2d |
static void controlled_drain(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int framesize;
|
|
Packit |
c32a2d |
size_t drain_block;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
play_prebuffer();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(intflag || !out123_buffered(ao))
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
if(out123_getformat(ao, NULL, NULL, NULL, &framesize))
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
drain_block = 1152*framesize;
|
|
Packit |
c32a2d |
if(param.verbose)
|
|
Packit |
c32a2d |
fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
do
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
out123_ndrain(ao, drain_block);
|
|
Packit |
c32a2d |
if(param.verbose)
|
|
Packit |
c32a2d |
print_buf("Draining buffer: ", ao);
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(param.term_ctrl)
|
|
Packit |
c32a2d |
term_control(mh, ao);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
while(!intflag && out123_buffered(ao));
|
|
Packit |
c32a2d |
if(param.verbose)
|
|
Packit |
c32a2d |
fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void safe_exit(int code)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char *dummy, *dammy;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(prebuffer)
|
|
Packit |
c32a2d |
free(prebuffer);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
dump_close();
|
|
Packit |
c32a2d |
if(!code)
|
|
Packit |
c32a2d |
controlled_drain();
|
|
Packit |
c32a2d |
if(intflag)
|
|
Packit |
c32a2d |
out123_drop(ao);
|
|
Packit |
c32a2d |
out123_del(ao);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(mh != NULL) mpg123_delete(mh);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(cleanup_mpg123) mpg123_exit();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
httpdata_free(&htd);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef WANT_WIN32_UNICODE
|
|
Packit |
c32a2d |
win32_cmdline_free(argc, argv); /* This handles the premature argv == NULL, too. */
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#if defined (WANT_WIN32_SOCKETS)
|
|
Packit |
c32a2d |
win32_net_deinit();
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
/* It's ugly... but let's just fix this still-reachable memory chunk of static char*. */
|
|
Packit |
c32a2d |
split_dir_file("", &dummy, &dammy);
|
|
Packit |
c32a2d |
if(fullprogname) free(fullprogname);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
term_exit();
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
exit(code);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void check_fatal_output(int code)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(code)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!param.quiet)
|
|
Packit |
c32a2d |
error2( "out123 error %i: %s"
|
|
Packit |
c32a2d |
, out123_errcode(ao), out123_strerror(ao) );
|
|
Packit |
c32a2d |
safe_exit(code);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output_module( char *arg )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
unsigned int i;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Search for a colon and set the device if found */
|
|
Packit |
c32a2d |
for(i=0; i< strlen( arg ); i++) {
|
|
Packit |
c32a2d |
if (arg[i] == ':') {
|
|
Packit |
c32a2d |
arg[i] = 0;
|
|
Packit |
c32a2d |
param.output_device = &arg[i+1];
|
|
Packit |
c32a2d |
debug1("Setting output device: %s", param.output_device);
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Set the output module */
|
|
Packit |
c32a2d |
param.output_module = arg;
|
|
Packit |
c32a2d |
debug1("Setting output module: %s", param.output_module );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output_flag(int flag)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(param.output_flags <= 0) param.output_flags = flag;
|
|
Packit |
c32a2d |
else param.output_flags |= flag;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output_h(char *a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
set_output_flag(OUT123_HEADPHONES);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output_s(char *a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
set_output_flag(OUT123_INTERNAL_SPEAKER);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output_l(char *a)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
set_output_flag(OUT123_LINE_OUT);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_output(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* If single letter, it's the legacy output switch for AIX/HP/Sun.
|
|
Packit |
c32a2d |
If longer, it's module[:device] . If zero length, it's rubbish. */
|
|
Packit |
c32a2d |
if(strlen(arg) <= 1) switch(arg[0])
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
case 'h': set_output_h(arg); break;
|
|
Packit |
c32a2d |
case 's': set_output_s(arg); break;
|
|
Packit |
c32a2d |
case 'l': set_output_l(arg); break;
|
|
Packit |
c32a2d |
default:
|
|
Packit |
c32a2d |
error1("\"%s\" is no valid output", arg);
|
|
Packit |
c32a2d |
safe_exit(1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else set_output_module(arg);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_verbose (char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.verbose++;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_quiet (char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.verbose=0;
|
|
Packit |
c32a2d |
param.quiet=TRUE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_out_wav(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "wav";
|
|
Packit |
c32a2d |
param.output_device = arg;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void set_out_cdr(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "cdr";
|
|
Packit |
c32a2d |
param.output_device = arg;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void set_out_au(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "au";
|
|
Packit |
c32a2d |
param.output_device = arg;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void set_out_test(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "test";
|
|
Packit |
c32a2d |
param.output_device = NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_out_file(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "raw";
|
|
Packit |
c32a2d |
param.output_device = arg;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_out_stdout(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "raw";
|
|
Packit |
c32a2d |
param.output_device = NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void set_out_stdout1(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.output_module = "raw";
|
|
Packit |
c32a2d |
param.output_device = NULL;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if !defined (HAVE_SCHED_SETSCHEDULER) && !defined (HAVE_WINDOWS_H)
|
|
Packit |
c32a2d |
static void realtime_not_compiled(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(stderr,"Option '-T / --realtime' not compiled into this binary.\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int frameflag; /* ugly, but that's the way without hacking getlopt */
|
|
Packit |
c32a2d |
static void set_frameflag(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Only one mono flag at a time! */
|
|
Packit |
c32a2d |
if(frameflag & MPG123_FORCE_MONO) param.flags &= ~MPG123_FORCE_MONO;
|
|
Packit |
c32a2d |
param.flags |= frameflag;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
static void unset_frameflag(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.flags &= ~frameflag;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int appflag; /* still ugly, but works */
|
|
Packit |
c32a2d |
static void set_appflag(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.appflags |= appflag;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void list_output_modules(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char **names = NULL;
|
|
Packit |
c32a2d |
char **descr = NULL;
|
|
Packit |
c32a2d |
int count = -1;
|
|
Packit |
c32a2d |
out123_handle *lao;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if((lao=out123_new()))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
printf("\n");
|
|
Packit |
c32a2d |
printf("Available modules\n");
|
|
Packit |
c32a2d |
printf("-----------------\n");
|
|
Packit |
c32a2d |
out123_param_string(lao, OUT123_BINDIR, binpath);
|
|
Packit |
c32a2d |
out123_param_int(lao, OUT123_VERBOSE, param.verbose);
|
|
Packit |
c32a2d |
if(param.quiet)
|
|
Packit |
c32a2d |
out123_param_int(lao, OUT123_FLAGS, OUT123_QUIET);
|
|
Packit |
c32a2d |
if((count=out123_drivers(lao, &names, &descr)) >= 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int i;
|
|
Packit |
c32a2d |
for(i=0; i
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
printf( "%-15s%s %s\n"
|
|
Packit |
c32a2d |
, names[i], "output", descr[i] );
|
|
Packit |
c32a2d |
free(names[i]);
|
|
Packit |
c32a2d |
free(descr[i]);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
free(names);
|
|
Packit |
c32a2d |
free(descr);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
out123_del(lao);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if(!param.quiet)
|
|
Packit |
c32a2d |
error("Failed to create an out123 handle.");
|
|
Packit |
c32a2d |
exit(count >= 0 ? 0 : 1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* static void unset_appflag(char *arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.appflags &= ~appflag;
|
|
Packit |
c32a2d |
} */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Please note: GLO_NUM expects point to LONG! */
|
|
Packit |
c32a2d |
/* ThOr:
|
|
Packit |
c32a2d |
* Yeah, and despite that numerous addresses to int variables were
|
|
Packit |
c32a2d |
passed.
|
|
Packit |
c32a2d |
* That's not good on my Alpha machine with int=32bit and long=64bit!
|
|
Packit |
c32a2d |
* Introduced GLO_INT and GLO_LONG as different bits to make that clear.
|
|
Packit |
c32a2d |
* GLO_NUM no longer exists.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
#ifdef OPT_3DNOW
|
|
Packit |
c32a2d |
static int dnow = 0; /* helper for mapping the old 3dnow options */
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
topt opts[] = {
|
|
Packit |
c32a2d |
{'k', "skip", GLO_ARG | GLO_LONG, 0, ¶m.start_frame, 0},
|
|
Packit |
c32a2d |
{'2', "2to1", GLO_INT, 0, ¶m.down_sample, 1},
|
|
Packit |
c32a2d |
{'4', "4to1", GLO_INT, 0, ¶m.down_sample, 2},
|
|
Packit |
c32a2d |
{'t', "test", GLO_INT, set_out_test, NULL, 0},
|
|
Packit |
c32a2d |
{'s', "stdout", GLO_INT, set_out_stdout, NULL, 0},
|
|
Packit |
c32a2d |
{'S', "STDOUT", GLO_INT, set_out_stdout1, NULL, 0},
|
|
Packit |
c32a2d |
{'O', "outfile", GLO_ARG | GLO_CHAR, set_out_file, NULL, 0},
|
|
Packit |
c32a2d |
{'c', "check", GLO_INT, 0, ¶m.checkrange, TRUE},
|
|
Packit |
c32a2d |
{'v', "verbose", 0, set_verbose, 0, 0},
|
|
Packit |
c32a2d |
{'q', "quiet", 0, set_quiet, 0, 0},
|
|
Packit |
c32a2d |
{'y', "no-resync", GLO_INT, set_frameflag, &frameflag, MPG123_NO_RESYNC},
|
|
Packit |
c32a2d |
/* compatibility, no-resync is to be used nowadays */
|
|
Packit |
c32a2d |
{0, "resync", GLO_INT, set_frameflag, &frameflag, MPG123_NO_RESYNC},
|
|
Packit |
c32a2d |
{'0', "single0", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_LEFT},
|
|
Packit |
c32a2d |
{0, "left", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_LEFT},
|
|
Packit |
c32a2d |
{'1', "single1", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_RIGHT},
|
|
Packit |
c32a2d |
{0, "right", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_RIGHT},
|
|
Packit |
c32a2d |
{'m', "singlemix", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_MIX},
|
|
Packit |
c32a2d |
{0, "mix", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_MIX},
|
|
Packit |
c32a2d |
{0, "mono", GLO_INT, set_frameflag, &frameflag, MPG123_MONO_MIX},
|
|
Packit |
c32a2d |
{0, "stereo", GLO_INT, set_frameflag, &frameflag, MPG123_FORCE_STEREO},
|
|
Packit |
c32a2d |
{0, "reopen", GLO_INT, 0, ¶m.force_reopen, 1},
|
|
Packit |
c32a2d |
{'g', "gain", GLO_ARG | GLO_LONG, 0, ¶m.gain, 0},
|
|
Packit |
c32a2d |
{'r', "rate", GLO_ARG | GLO_LONG, 0, ¶m.force_rate, 0},
|
|
Packit |
c32a2d |
{0, "8bit", GLO_INT, set_frameflag, &frameflag, MPG123_FORCE_8BIT},
|
|
Packit |
c32a2d |
{0, "float", GLO_INT, set_frameflag, &frameflag, MPG123_FORCE_FLOAT},
|
|
Packit |
c32a2d |
{0, "headphones", 0, set_output_h, 0,0},
|
|
Packit |
c32a2d |
{0, "speaker", 0, set_output_s, 0,0},
|
|
Packit |
c32a2d |
{0, "lineout", 0, set_output_l, 0,0},
|
|
Packit |
c32a2d |
{'o', "output", GLO_ARG | GLO_CHAR, set_output, 0, 0},
|
|
Packit |
c32a2d |
{0, "list-modules",0, list_output_modules, NULL, 0},
|
|
Packit |
c32a2d |
{'a', "audiodevice", GLO_ARG | GLO_CHAR, 0, ¶m.output_device, 0},
|
|
Packit |
c32a2d |
{'f', "scale", GLO_ARG | GLO_LONG, 0, ¶m.outscale, 0},
|
|
Packit |
c32a2d |
{'n', "frames", GLO_ARG | GLO_LONG, 0, ¶m.frame_number, 0},
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
{'C', "control", GLO_INT, 0, ¶m.term_ctrl, TRUE},
|
|
Packit |
c32a2d |
{0, "no-control", GLO_INT, 0, ¶m.term_ctrl, FALSE},
|
|
Packit |
c32a2d |
{0, "ctrlusr1", GLO_ARG | GLO_CHAR, 0, ¶m.term_usr1, 0},
|
|
Packit |
c32a2d |
{0, "ctrlusr2", GLO_ARG | GLO_CHAR, 0, ¶m.term_usr2, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifndef NOXFERMEM
|
|
Packit |
c32a2d |
{'b', "buffer", GLO_ARG | GLO_LONG, 0, ¶m.usebuffer, 0},
|
|
Packit |
c32a2d |
{0, "smooth", GLO_INT, 0, ¶m.smooth, 1},
|
|
Packit |
c32a2d |
{0, "preload", GLO_ARG|GLO_DOUBLE, 0, ¶m.preload, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{'R', "remote", GLO_INT, 0, ¶m.remote, TRUE},
|
|
Packit |
c32a2d |
{0, "remote-err", GLO_INT, 0, ¶m.remote_err, TRUE},
|
|
Packit |
c32a2d |
{'d', "doublespeed", GLO_ARG | GLO_LONG, 0, ¶m.doublespeed, 0},
|
|
Packit |
c32a2d |
{'h', "halfspeed", GLO_ARG | GLO_LONG, 0, ¶m.halfspeed, 0},
|
|
Packit |
c32a2d |
#ifdef NETWORK
|
|
Packit |
c32a2d |
{'p', "proxy", GLO_ARG | GLO_CHAR, 0, ¶m.proxyurl, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{'@', "list", GLO_ARG | GLO_CHAR, 0, ¶m.listname, 0},
|
|
Packit |
c32a2d |
/* 'z' comes from the the german word 'zufall' (eng: random) */
|
|
Packit |
c32a2d |
{'z', "shuffle", GLO_INT, 0, ¶m.shuffle, 1},
|
|
Packit |
c32a2d |
{'Z', "random", GLO_INT, 0, ¶m.shuffle, 2},
|
|
Packit |
c32a2d |
{'E', "equalizer", GLO_ARG | GLO_CHAR, 0, &equalfile,1},
|
|
Packit |
c32a2d |
#ifdef HAVE_SETPRIORITY
|
|
Packit |
c32a2d |
{0, "aggressive", GLO_INT, 0, ¶m.aggressive, 2},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef OPT_3DNOW
|
|
Packit |
c32a2d |
#define SET_3DNOW 1
|
|
Packit |
c32a2d |
#define SET_I586 2
|
|
Packit |
c32a2d |
{0, "force-3dnow", GLO_CHAR, 0, &dnow, SET_3DNOW},
|
|
Packit |
c32a2d |
{0, "no-3dnow", GLO_CHAR, 0, &dnow, SET_I586},
|
|
Packit |
c32a2d |
{0, "test-3dnow", GLO_INT, 0, ¶m.test_cpu, TRUE},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{0, "cpu", GLO_ARG | GLO_CHAR, 0, ¶m.cpu, 0},
|
|
Packit |
c32a2d |
{0, "test-cpu", GLO_INT, 0, ¶m.test_cpu, TRUE},
|
|
Packit |
c32a2d |
{0, "list-cpu", GLO_INT, 0, ¶m.list_cpu , 1},
|
|
Packit |
c32a2d |
#ifdef NETWORK
|
|
Packit |
c32a2d |
{'u', "auth", GLO_ARG | GLO_CHAR, 0, &httpauth, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#if defined (HAVE_SCHED_SETSCHEDULER) || defined (HAVE_WINDOWS_H)
|
|
Packit |
c32a2d |
/* check why this should be a long variable instead of int! */
|
|
Packit |
c32a2d |
{'T', "realtime", GLO_LONG, 0, ¶m.realtime, TRUE },
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
{'T', "realtime", 0, realtime_not_compiled, 0, 0 },
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_WINDOWS_H
|
|
Packit |
c32a2d |
{0, "priority", GLO_ARG | GLO_INT, 0, ¶m.w32_priority, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{0, "title", GLO_INT, 0, ¶m.xterm_title, TRUE },
|
|
Packit |
c32a2d |
{'w', "wav", GLO_ARG | GLO_CHAR, set_out_wav, 0, 0 },
|
|
Packit |
c32a2d |
{0, "cdr", GLO_ARG | GLO_CHAR, set_out_cdr, 0, 0 },
|
|
Packit |
c32a2d |
{0, "au", GLO_ARG | GLO_CHAR, set_out_au, 0, 0 },
|
|
Packit |
c32a2d |
{0, "gapless", GLO_INT, set_frameflag, &frameflag, MPG123_GAPLESS},
|
|
Packit |
c32a2d |
{0, "no-gapless", GLO_INT, unset_frameflag, &frameflag, MPG123_GAPLESS},
|
|
Packit |
c32a2d |
{0, "no-infoframe", GLO_INT, set_frameflag, &frameflag, MPG123_IGNORE_INFOFRAME},
|
|
Packit |
c32a2d |
{'?', "help", 0, want_usage, 0, 0 },
|
|
Packit |
c32a2d |
{0 , "longhelp" , 0, want_long_usage, 0, 0 },
|
|
Packit |
c32a2d |
{0 , "version" , 0, give_version, 0, 0 },
|
|
Packit |
c32a2d |
{'l', "listentry", GLO_ARG | GLO_LONG, 0, ¶m.listentry, 0 },
|
|
Packit |
c32a2d |
{0, "continue", GLO_INT, set_appflag, &appflag, MPG123APP_CONTINUE },
|
|
Packit |
c32a2d |
{0, "rva-mix", GLO_INT, 0, ¶m.rva, 1 },
|
|
Packit |
c32a2d |
{0, "rva-radio", GLO_INT, 0, ¶m.rva, 1 },
|
|
Packit |
c32a2d |
{0, "rva-album", GLO_INT, 0, ¶m.rva, 2 },
|
|
Packit |
c32a2d |
{0, "rva-audiophile", GLO_INT, 0, ¶m.rva, 2 },
|
|
Packit |
c32a2d |
{0, "no-icy-meta", GLO_INT, 0, ¶m.talk_icy, 0 },
|
|
Packit |
c32a2d |
{0, "long-tag", GLO_INT, 0, ¶m.long_id3, 1 },
|
|
Packit |
c32a2d |
#ifdef FIFO
|
|
Packit |
c32a2d |
{0, "fifo", GLO_ARG | GLO_CHAR, 0, ¶m.fifo, 0},
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{0, "timeout", GLO_ARG | GLO_LONG, 0, ¶m.timeout, 0},
|
|
Packit |
c32a2d |
{0, "loop", GLO_ARG | GLO_LONG, 0, ¶m.loop, 0},
|
|
Packit |
c32a2d |
{'i', "index", GLO_INT, 0, ¶m.index, 1},
|
|
Packit |
c32a2d |
{'D', "delay", GLO_ARG | GLO_INT, 0, ¶m.delay, 0},
|
|
Packit |
c32a2d |
{0, "resync-limit", GLO_ARG | GLO_LONG, 0, ¶m.resync_limit, 0},
|
|
Packit |
c32a2d |
{0, "pitch", GLO_ARG|GLO_DOUBLE, 0, ¶m.pitch, 0},
|
|
Packit |
c32a2d |
#ifdef NETWORK
|
|
Packit |
c32a2d |
{0, "ignore-mime", GLO_INT, set_appflag, &appflag, MPG123APP_IGNORE_MIME },
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{0, "lyrics", GLO_INT, set_appflag, &appflag, MPG123APP_LYRICS},
|
|
Packit |
c32a2d |
{0, "keep-open", GLO_INT, 0, ¶m.keep_open, 1},
|
|
Packit |
c32a2d |
{0, "utf8", GLO_INT, 0, ¶m.force_utf8, 1},
|
|
Packit |
c32a2d |
{0, "fuzzy", GLO_INT, set_frameflag, &frameflag, MPG123_FUZZY},
|
|
Packit |
c32a2d |
{0, "index-size", GLO_ARG|GLO_LONG, 0, ¶m.index_size, 0},
|
|
Packit |
c32a2d |
{0, "no-seekbuffer", GLO_INT, unset_frameflag, &frameflag, MPG123_SEEKBUFFER},
|
|
Packit |
c32a2d |
{'e', "encoding", GLO_ARG|GLO_CHAR, 0, ¶m.force_encoding, 0},
|
|
Packit |
c32a2d |
{0, "preframes", GLO_ARG|GLO_LONG, 0, ¶m.preframes, 0},
|
|
Packit |
c32a2d |
{0, "skip-id3v2", GLO_INT, set_frameflag, &frameflag, MPG123_SKIP_ID3V2},
|
|
Packit |
c32a2d |
{0, "streamdump", GLO_ARG|GLO_CHAR, 0, ¶m.streamdump, 0},
|
|
Packit |
c32a2d |
{0, "icy-interval", GLO_ARG|GLO_LONG, 0, ¶m.icy_interval, 0},
|
|
Packit |
c32a2d |
{0, "ignore-streamlength", GLO_INT, set_frameflag, &frameflag, MPG123_IGNORE_STREAMLENGTH},
|
|
Packit |
c32a2d |
{0, "name", GLO_ARG|GLO_CHAR, 0, ¶m.name, 0},
|
|
Packit |
c32a2d |
{0, "devbuffer", GLO_ARG|GLO_DOUBLE, 0, ¶m.device_buffer, 0},
|
|
Packit |
c32a2d |
{0, 0, 0, 0, 0, 0}
|
|
Packit |
c32a2d |
};
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static int open_track_fd (void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Let reader handle invalid filept */
|
|
Packit |
c32a2d |
if(mpg123_open_fd(mh, filept) != MPG123_OK)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error2("Cannot open fd %i: %s", filept, mpg123_strerror(mh));
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
debug("Track successfully opened.");
|
|
Packit |
c32a2d |
fresh = TRUE;
|
|
Packit |
c32a2d |
return 1;
|
|
Packit |
c32a2d |
/*1 for success, 0 for failure */
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* 1 on success, 0 on failure */
|
|
Packit |
c32a2d |
int open_track(char *fname)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
filept=-1;
|
|
Packit |
c32a2d |
httpdata_reset(&htd);
|
|
Packit |
c32a2d |
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, 0, 0))
|
|
Packit |
c32a2d |
error1("Cannot (re)set ICY interval: %s", mpg123_strerror(mh));
|
|
Packit |
c32a2d |
if(!strcmp(fname, "-"))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
filept = STDIN_FILENO;
|
|
Packit |
c32a2d |
#ifdef WIN32
|
|
Packit |
c32a2d |
_setmode(STDIN_FILENO, _O_BINARY);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if (!strncmp(fname, "http://", 7)) /* http stream */
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
#if defined (WANT_WIN32_SOCKETS)
|
|
Packit |
c32a2d |
if(param.streamdump != NULL)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(stderr, "\nWarning: win32 networking conflicts with stream dumping. Aborting the dump.\n");
|
|
Packit |
c32a2d |
dump_close();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/*Use recv instead of stdio functions */
|
|
Packit |
c32a2d |
win32_net_replace(mh);
|
|
Packit |
c32a2d |
filept = win32_net_http_open(fname, &htd);
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
filept = http_open(fname, &htd);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
network_sockets_used = 1;
|
|
Packit |
c32a2d |
/* utf-8 encoded URLs might not work under Win32 */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* now check if we got sth. and if we got sth. good */
|
|
Packit |
c32a2d |
if( (filept >= 0) && (htd.content_type.p != NULL)
|
|
Packit |
c32a2d |
&& !APPFLAG(MPG123APP_IGNORE_MIME) && !(debunk_mime(htd.content_type.p) & IS_FILE) )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Unknown mpeg MIME type %s - is it perhaps a playlist (use -@)?", htd.content_type.p == NULL ? "<nil>" : htd.content_type.p);
|
|
Packit |
c32a2d |
error("If you know the stream is mpeg1/2 audio, then please report this as "PACKAGE_NAME" bug");
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(filept < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Access to http resource %s failed.", fname);
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, htd.icy_interval, 0))
|
|
Packit |
c32a2d |
error1("Cannot set ICY interval: %s", mpg123_strerror(mh));
|
|
Packit |
c32a2d |
if(param.verbose > 1) fprintf(stderr, "Info: ICY interval %li\n", (long)htd.icy_interval);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(param.icy_interval > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(MPG123_OK != mpg123_param(mh, MPG123_ICY_INTERVAL, param.icy_interval, 0))
|
|
Packit |
c32a2d |
error1("Cannot set ICY interval: %s", mpg123_strerror(mh));
|
|
Packit |
c32a2d |
if(param.verbose > 1) fprintf(stderr, "Info: Forced ICY interval %li\n", param.icy_interval);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
debug("OK... going to finally open.");
|
|
Packit |
c32a2d |
/* Now hook up the decoder on the opened stream or the file. */
|
|
Packit |
c32a2d |
if(filept > -1)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
return open_track_fd();
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if(mpg123_open(mh, fname) != MPG123_OK)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error2("Cannot open %s: %s", fname, mpg123_strerror(mh));
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
debug("Track successfully opened.");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fresh = TRUE;
|
|
Packit |
c32a2d |
return 1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* for symmetry */
|
|
Packit |
c32a2d |
void close_track(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
mpg123_close(mh);
|
|
Packit |
c32a2d |
#if defined (WANT_WIN32_SOCKETS)
|
|
Packit |
c32a2d |
if (network_sockets_used)
|
|
Packit |
c32a2d |
win32_net_close(filept);
|
|
Packit |
c32a2d |
filept = -1;
|
|
Packit |
c32a2d |
return;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
network_sockets_used = 0;
|
|
Packit |
c32a2d |
if(filept > -1) close(filept);
|
|
Packit |
c32a2d |
filept = -1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* return 1 on success, 0 on failure */
|
|
Packit |
c32a2d |
int play_frame(void)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
unsigned char *audio;
|
|
Packit |
c32a2d |
int mc;
|
|
Packit |
c32a2d |
size_t bytes = 0;
|
|
Packit |
c32a2d |
debug("play_frame");
|
|
Packit |
c32a2d |
mc = mpg123_decode_frame(mh, &framenum, &audio, &bytes);
|
|
Packit |
c32a2d |
mpg123_getstate(mh, MPG123_FRESH_DECODER, &new_header, NULL);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Play what is there to play (starting with second decode_frame call!) */
|
|
Packit |
c32a2d |
if(bytes)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(param.frame_number > -1) --frames_left;
|
|
Packit |
c32a2d |
if(fresh && framenum >= param.start_frame)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fresh = FALSE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(bytes < minbytes && !prebuffer_fill)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Postpone playback of little buffers until large buffers can
|
|
Packit |
c32a2d |
follow them right away, preventing underruns. */
|
|
Packit |
c32a2d |
if(prebuffer_size < minbytes)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(prebuffer)
|
|
Packit |
c32a2d |
free(prebuffer);
|
|
Packit |
c32a2d |
if(!(prebuffer = malloc(minbytes)))
|
|
Packit |
c32a2d |
safe_exit(11);
|
|
Packit |
c32a2d |
prebuffer_size = minbytes;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
memcpy(prebuffer, audio, bytes);
|
|
Packit |
c32a2d |
prebuffer_fill = bytes;
|
|
Packit |
c32a2d |
bytes = 0;
|
|
Packit |
c32a2d |
debug1("prebuffered %"SIZE_P" bytes", prebuffer_fill);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(param.checkrange)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
long clip = mpg123_clip(mh);
|
|
Packit |
c32a2d |
if(clip > 0) fprintf(stderr,"\n%ld samples clipped\n", clip);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* The bytes could have been postponed to later. */
|
|
Packit |
c32a2d |
if(bytes)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
unsigned char *playbuf = audio;
|
|
Packit |
c32a2d |
if(prebuffer_fill)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t missing;
|
|
Packit |
c32a2d |
/* This is tricky: The small piece needs to be filled up. Playing 10
|
|
Packit |
c32a2d |
pcm frames will always trigger underruns with ALSA, dammit!
|
|
Packit |
c32a2d |
This grabs some data from current frame, unless it itself would
|
|
Packit |
c32a2d |
end up smaller than the prebuffer. Ending up empty is fine. */
|
|
Packit |
c32a2d |
if( prebuffer_fill < prebuffer_size
|
|
Packit |
c32a2d |
&& ( bytes <= (missing=prebuffer_size-prebuffer_fill)
|
|
Packit |
c32a2d |
|| bytes >= missing+prebuffer_size ) )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(bytes < missing)
|
|
Packit |
c32a2d |
missing=bytes;
|
|
Packit |
c32a2d |
memcpy(prebuffer+prebuffer_fill, playbuf, missing);
|
|
Packit |
c32a2d |
playbuf += missing;
|
|
Packit |
c32a2d |
bytes -= missing;
|
|
Packit |
c32a2d |
prebuffer_fill += missing;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if( out123_play(ao, prebuffer, prebuffer_fill) < prebuffer_fill
|
|
Packit |
c32a2d |
&& !intflag )
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("Deep trouble! Cannot flush to my output anymore!");
|
|
Packit |
c32a2d |
safe_exit(133);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
prebuffer_fill = 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Interrupt here doesn't necessarily interrupt out123_play().
|
|
Packit |
c32a2d |
I wonder if that makes us miss errors. Actual issues should
|
|
Packit |
c32a2d |
just be postponed. */
|
|
Packit |
c32a2d |
if(bytes && !intflag) /* Previous piece could already be interrupted. */
|
|
Packit |
c32a2d |
if(out123_play(ao, playbuf, bytes) < bytes && !intflag)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("Deep trouble! Cannot flush to my output anymore!");
|
|
Packit |
c32a2d |
safe_exit(133);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Special actions and errors. */
|
|
Packit |
c32a2d |
if(mc != MPG123_OK)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(mc == MPG123_ERR || mc == MPG123_DONE)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(mc == MPG123_ERR) error1("...in decoding next frame: %s", mpg123_strerror(mh));
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(mc == MPG123_NO_SPACE)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("I have not enough output space? I didn't plan for this.");
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(mc == MPG123_NEW_FORMAT)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
long rate;
|
|
Packit |
c32a2d |
int channels;
|
|
Packit |
c32a2d |
int encoding;
|
|
Packit |
c32a2d |
play_prebuffer(); /* Make sure we got rid of old data. */
|
|
Packit |
c32a2d |
mpg123_getformat(mh, &rate, &channels, &encoding);
|
|
Packit |
c32a2d |
/* A layer I frame duration at minimum for live outputs. */
|
|
Packit |
c32a2d |
if(output_propflags & OUT123_PROP_LIVE)
|
|
Packit |
c32a2d |
minbytes = out123_encsize(encoding)*channels*384;
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
minbytes = 0;
|
|
Packit |
c32a2d |
if(param.verbose > 2)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const char* encname = out123_enc_name(encoding);
|
|
Packit |
c32a2d |
fprintf( stderr
|
|
Packit |
c32a2d |
, "\nNote: New output format with %li Hz, %i channels, encoding %s.\n"
|
|
Packit |
c32a2d |
, rate, channels, encname ? encname : "???" );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
new_header = TRUE;
|
|
Packit |
c32a2d |
check_fatal_output(out123_start(ao, rate, channels, encoding));
|
|
Packit |
c32a2d |
/* We may take some time feeding proper data, so pause by default. */
|
|
Packit |
c32a2d |
out123_pause(ao);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(new_header && !param.quiet)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
new_header = FALSE;
|
|
Packit |
c32a2d |
fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
if(param.verbose > 1)
|
|
Packit |
c32a2d |
print_header(mh);
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
print_header_compact(mh);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
return 1;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Return TRUE if we should continue (second interrupt happens quickly), skipping tracks, or FALSE if we should die. */
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
int skip_or_die(struct timeval *start_time)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* Death is fatal right away. */
|
|
Packit |
c32a2d |
if(deathflag)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("The world wants me to die.");
|
|
Packit |
c32a2d |
return FALSE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
* When HAVE_TERMIOS is defined, there is 'q' to terminate a list of songs, so
|
|
Packit |
c32a2d |
* no pressing need to keep up this first second SIGINT hack that was too
|
|
Packit |
c32a2d |
* often mistaken as a bug. [dk]
|
|
Packit |
c32a2d |
* ThOr: Yep, I deactivated the Ctrl+C hack for active control modes.
|
|
Packit |
c32a2d |
* Though, some sort of hack remains, still using intflag for track skip.
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(!param.term_ctrl)
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
struct timeval now;
|
|
Packit |
c32a2d |
unsigned long secdiff;
|
|
Packit |
c32a2d |
gettimeofday (&now, NULL);
|
|
Packit |
c32a2d |
secdiff = (now.tv_sec - start_time->tv_sec) * 1000;
|
|
Packit |
c32a2d |
if(now.tv_usec >= start_time->tv_usec)
|
|
Packit |
c32a2d |
secdiff += (now.tv_usec - start_time->tv_usec) / 1000;
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
secdiff -= (start_time->tv_usec - now.tv_usec) / 1000;
|
|
Packit |
c32a2d |
if (secdiff < 1000)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("got the second interrupt: out of here!");
|
|
Packit |
c32a2d |
return FALSE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("It's a track advancement message.");
|
|
Packit |
c32a2d |
++skip_tracks;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
else if(skip_tracks == 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("breaking up");
|
|
Packit |
c32a2d |
return FALSE;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
return TRUE; /* Track advancement... no instant kill on generic/windows... */
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
/* On generic systems and win32, there is no decision here... just TRUE. */
|
|
Packit |
c32a2d |
#define skip_or_die(a) TRUE
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
int main(int sys_argc, char ** sys_argv)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int result;
|
|
Packit |
c32a2d |
char end_of_files = FALSE;
|
|
Packit |
c32a2d |
long parr;
|
|
Packit |
c32a2d |
char *fname;
|
|
Packit |
c32a2d |
int libpar = 0;
|
|
Packit |
c32a2d |
mpg123_pars *mp;
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
struct timeval start_time;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
aux_out = stdout; /* Need to initialize here because stdout is not a constant?! */
|
|
Packit |
c32a2d |
#if defined (WANT_WIN32_UNICODE)
|
|
Packit |
c32a2d |
if(win32_cmdline_utf8(&argc, &argv) != 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("Cannot convert command line to UTF8!");
|
|
Packit |
c32a2d |
safe_exit(76);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
argv = sys_argv;
|
|
Packit |
c32a2d |
argc = sys_argc;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#if defined (WANT_WIN32_SOCKETS)
|
|
Packit |
c32a2d |
win32_net_init();
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef WIN32
|
|
Packit |
c32a2d |
/* Despite in Unicode form, the path munging backend is still in ANSI/ASCII
|
|
Packit |
c32a2d |
* so using _wpgmptr with unicode paths after UTF8 conversion is broken on Windows
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fullprogname = compat_strdup(_pgmptr);
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
fullprogname = compat_strdup(argv[0]);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!fullprogname)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("OOM"); /* Out Of Memory. Don't waste bytes on that error. */
|
|
Packit |
c32a2d |
safe_exit(1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Extract binary and path, take stuff before/after last / or \ . */
|
|
Packit |
c32a2d |
if( (prgName = strrchr(fullprogname, '/'))
|
|
Packit |
c32a2d |
|| (prgName = strrchr(fullprogname, '\\')))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
/* There is some explicit path. */
|
|
Packit |
c32a2d |
prgName[0] = 0; /* End byte for path. */
|
|
Packit |
c32a2d |
prgName++;
|
|
Packit |
c32a2d |
binpath = fullprogname;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
prgName = fullprogname; /* No path separators there. */
|
|
Packit |
c32a2d |
binpath = NULL; /* No path at all. */
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Need to initialize mpg123 lib here for default parameter values. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
result = mpg123_init();
|
|
Packit |
c32a2d |
if(result != MPG123_OK)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Cannot initialize mpg123 library: %s", mpg123_plain_strerror(result));
|
|
Packit |
c32a2d |
safe_exit(77);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
cleanup_mpg123 = TRUE;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mp = mpg123_new_pars(&result); /* This may get leaked on premature exit(), which is mainly a cosmetic issue... */
|
|
Packit |
c32a2d |
if(mp == NULL)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Crap! Cannot get mpg123 parameters: %s", mpg123_plain_strerror(result));
|
|
Packit |
c32a2d |
safe_exit(78);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* get default values */
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_DOWN_SAMPLE, &parr, NULL);
|
|
Packit |
c32a2d |
param.down_sample = (int) parr;
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_RVA, ¶m.rva, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_DOWNSPEED, ¶m.halfspeed, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_UPSPEED, ¶m.doublespeed, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_OUTSCALE, ¶m.outscale, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_FLAGS, &parr, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_INDEX_SIZE, ¶m.index_size, NULL);
|
|
Packit |
c32a2d |
param.flags = (int) parr;
|
|
Packit |
c32a2d |
param.flags |= MPG123_SEEKBUFFER; /* Default on, for HTTP streams. */
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_RESYNC_LIMIT, ¶m.resync_limit, NULL);
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_PREFRAMES, ¶m.preframes, NULL);
|
|
Packit |
c32a2d |
/* Also need proper default flags from libout123. */
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
out123_handle *paro = out123_new();
|
|
Packit |
c32a2d |
out123_getparam_int(paro, OUT123_FLAGS, ¶m.output_flags);
|
|
Packit |
c32a2d |
out123_del(paro);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef OS2
|
|
Packit |
c32a2d |
_wildcard(&argc,&argv);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
/* Detect terminal on input side, enable control by default. */
|
|
Packit |
c32a2d |
param.term_ctrl = !(term_width(STDIN_FILENO) < 0);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
while ((result = getlopt(argc, argv, opts)))
|
|
Packit |
c32a2d |
switch (result) {
|
|
Packit |
c32a2d |
case GLO_UNKNOWN:
|
|
Packit |
c32a2d |
fprintf (stderr, "%s: Unknown option \"%s\".\n",
|
|
Packit |
c32a2d |
prgName, loptarg);
|
|
Packit |
c32a2d |
usage(1);
|
|
Packit |
c32a2d |
case GLO_NOARG:
|
|
Packit |
c32a2d |
fprintf (stderr, "%s: Missing argument for option \"%s\".\n",
|
|
Packit |
c32a2d |
prgName, loptarg);
|
|
Packit |
c32a2d |
usage(1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/* Do this _after_ parameter parsing. */
|
|
Packit |
c32a2d |
check_locale(); /* Check/set locale; store if it uses UTF-8. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(param.list_cpu)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const char **all_dec = mpg123_decoders();
|
|
Packit |
c32a2d |
printf("Builtin decoders:");
|
|
Packit |
c32a2d |
while(*all_dec != NULL){ printf(" %s", *all_dec); ++all_dec; }
|
|
Packit |
c32a2d |
printf("\n");
|
|
Packit |
c32a2d |
mpg123_delete_pars(mp);
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(param.test_cpu)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const char **all_dec = mpg123_supported_decoders();
|
|
Packit |
c32a2d |
printf("Supported decoders:");
|
|
Packit |
c32a2d |
while(*all_dec != NULL){ printf(" %s", *all_dec); ++all_dec; }
|
|
Packit |
c32a2d |
printf("\n");
|
|
Packit |
c32a2d |
mpg123_delete_pars(mp);
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(param.gain != -1)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
warning("The parameter -g is deprecated and may be removed in the future.");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (loptind >= argc && !param.listname && !param.remote) usage(1);
|
|
Packit |
c32a2d |
/* Init audio as early as possible.
|
|
Packit |
c32a2d |
If there is the buffer process to be spawned, it shouldn't carry the mpg123_handle with it. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* ========================================================================================================= */
|
|
Packit |
c32a2d |
/* Enterning the leaking zone... we start messing with stuff here that should be taken care of when leaving. */
|
|
Packit |
c32a2d |
/* Don't just exit() or return out... */
|
|
Packit |
c32a2d |
/* ========================================================================================================= */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
httpdata_init(&htd);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
if(param.remote && !param.verbose)
|
|
Packit |
c32a2d |
param.quiet = 1;
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Set the frame parameters from command line options */
|
|
Packit |
c32a2d |
if(param.quiet)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
param.flags |= MPG123_QUIET;
|
|
Packit |
c32a2d |
param.output_flags |= OUT123_QUIET;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef OPT_3DNOW
|
|
Packit |
c32a2d |
if(dnow != 0) param.cpu = (dnow == SET_3DNOW) ? "3dnow" : "i586";
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
if(param.cpu != NULL && (!strcmp(param.cpu, "auto") || !strcmp(param.cpu, ""))) param.cpu = NULL;
|
|
Packit |
c32a2d |
if(!( MPG123_OK == (result = mpg123_par(mp, MPG123_VERBOSE, param.verbose, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_FLAGS, param.flags, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_DOWN_SAMPLE, param.down_sample, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_RVA, param.rva, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_FORCE_RATE, param.force_rate, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_DOWNSPEED, param.halfspeed, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_UPSPEED, param.doublespeed, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_ICY_INTERVAL, 0, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_RESYNC_LIMIT, param.resync_limit, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_TIMEOUT, param.timeout, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_OUTSCALE, param.outscale, 0))
|
|
Packit |
c32a2d |
&& ++libpar
|
|
Packit |
c32a2d |
&& MPG123_OK == (result = mpg123_par(mp, MPG123_PREFRAMES, param.preframes, 0))
|
|
Packit |
c32a2d |
))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error2("Cannot set library parameter %i: %s", libpar, mpg123_plain_strerror(result));
|
|
Packit |
c32a2d |
safe_exit(45);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if (!(param.listentry < 0) && !param.quiet) print_title(stderr); /* do not pollute stdout! */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
long default_index;
|
|
Packit |
c32a2d |
mpg123_getpar(mp, MPG123_INDEX_SIZE, &default_index, NULL);
|
|
Packit |
c32a2d |
if( param.index_size != default_index && (result = mpg123_par(mp, MPG123_INDEX_SIZE, param.index_size, 0.)) != MPG123_OK )
|
|
Packit |
c32a2d |
error1("Setting of frame index size failed: %s", mpg123_plain_strerror(result));
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(param.force_rate && param.down_sample)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error("Down sampling and fixed rate options not allowed together!");
|
|
Packit |
c32a2d |
safe_exit(1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Now actually get an mpg123_handle. */
|
|
Packit |
c32a2d |
mh = mpg123_parnew(mp, param.cpu, &result);
|
|
Packit |
c32a2d |
if(mh == NULL)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Crap! Cannot get a mpg123 handle: %s", mpg123_plain_strerror(result));
|
|
Packit |
c32a2d |
safe_exit(77);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
mpg123_delete_pars(mp); /* Don't need the parameters anymore ,they're in the handle now. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Prepare stream dumping, possibly replacing mpg123 reader. */
|
|
Packit |
c32a2d |
if(dump_open(mh) != 0) safe_exit(78);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
load_equalizer(mh);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_SETPRIORITY
|
|
Packit |
c32a2d |
if(param.aggressive) { /* tst */
|
|
Packit |
c32a2d |
int mypid = getpid();
|
|
Packit |
c32a2d |
if(!param.quiet) fprintf(stderr,"Aggressively trying to increase priority.\n");
|
|
Packit |
c32a2d |
if(setpriority(PRIO_PROCESS,mypid,-20))
|
|
Packit |
c32a2d |
error("Failed to aggressively increase priority.\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if defined (HAVE_SCHED_SETSCHEDULER) && !defined (__CYGWIN__) && !defined (HAVE_WINDOWS_H)
|
|
Packit |
c32a2d |
/* Cygwin --realtime seems to fail when accessing network, using win32 set priority instead */
|
|
Packit |
c32a2d |
/* MinGW may have pthread installed, we prefer win32API */
|
|
Packit |
c32a2d |
if (param.realtime) { /* Get real-time priority */
|
|
Packit |
c32a2d |
struct sched_param sp;
|
|
Packit |
c32a2d |
fprintf(stderr,"Getting real-time priority\n");
|
|
Packit |
c32a2d |
memset(&sp, 0, sizeof(struct sched_param));
|
|
Packit |
c32a2d |
sp.sched_priority = sched_get_priority_min(SCHED_FIFO);
|
|
Packit |
c32a2d |
if (sched_setscheduler(0, SCHED_RR, &sp) == -1)
|
|
Packit |
c32a2d |
error("Can't get realtime priority\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* make sure not Cygwin, it doesn't need it */
|
|
Packit |
c32a2d |
#if defined(WIN32) && defined(HAVE_WINDOWS_H)
|
|
Packit |
c32a2d |
/* argument "3" is equivalent to realtime priority class */
|
|
Packit |
c32a2d |
win32_set_priority( param.realtime ? 3 : param.w32_priority);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* TODO: There's some memory leaking on fatal safe_exits().
|
|
Packit |
c32a2d |
This is a cosmetic issue, though. */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Initializing output after the priority stuff, might influence
|
|
Packit |
c32a2d |
buffer process. */
|
|
Packit |
c32a2d |
ao = out123_new();
|
|
Packit |
c32a2d |
if(!ao)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!param.quiet)
|
|
Packit |
c32a2d |
error("Failed to allocate output.");
|
|
Packit |
c32a2d |
safe_exit(97);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if
|
|
Packit |
c32a2d |
( 0
|
|
Packit |
c32a2d |
|| out123_param_int(ao, OUT123_FLAGS, param.output_flags)
|
|
Packit |
c32a2d |
|| out123_param_float(ao, OUT123_PRELOAD, param.preload)
|
|
Packit |
c32a2d |
|| out123_param_int(ao, OUT123_GAIN, param.gain)
|
|
Packit |
c32a2d |
|| out123_param_int(ao, OUT123_VERBOSE, param.verbose)
|
|
Packit |
c32a2d |
|| out123_param_string(ao, OUT123_NAME, param.name)
|
|
Packit |
c32a2d |
|| out123_param_string(ao, OUT123_BINDIR, binpath)
|
|
Packit |
c32a2d |
|| out123_param_float(ao, OUT123_DEVICEBUFFER, param.device_buffer)
|
|
Packit |
c32a2d |
)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!param.quiet)
|
|
Packit |
c32a2d |
error("Error setting output parameters. Do you need a usage reminder?");
|
|
Packit |
c32a2d |
safe_exit(98);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
check_fatal_output(out123_set_buffer(ao, param.usebuffer*1024));
|
|
Packit |
c32a2d |
check_fatal_output(out123_open( ao
|
|
Packit |
c32a2d |
, param.output_module, param.output_device ));
|
|
Packit |
c32a2d |
out123_getparam_int(ao, OUT123_PROPFLAGS, &output_propflags);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!param.remote) prepare_playlist(argc, argv);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
/* Remote mode is special... but normal console and terminal-controlled operation needs to catch the SIGINT.
|
|
Packit |
c32a2d |
For one it serves for track skip when not in terminal control mode.
|
|
Packit |
c32a2d |
The more important use being a graceful exit, including telling the buffer process what's going on. */
|
|
Packit |
c32a2d |
if(!param.remote)
|
|
Packit |
c32a2d |
catchsignal(SIGINT, catch_interrupt);
|
|
Packit |
c32a2d |
/* Need to catch things to exit cleanly, not messing up the terminal. */
|
|
Packit |
c32a2d |
catchsignal(SIGTERM, catch_fatal_term);
|
|
Packit |
c32a2d |
catchsignal(SIGPIPE, catch_fatal_pipe);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
/* Now either check caps myself or query buffer for that. */
|
|
Packit |
c32a2d |
audio_capabilities(ao, mh);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(param.remote) {
|
|
Packit |
c32a2d |
int ret;
|
|
Packit |
c32a2d |
ret = control_generic(mh);
|
|
Packit |
c32a2d |
safe_exit(ret);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
term_init();
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
if(APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
while ((fname = get_next_file()))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
char *dirname, *filename;
|
|
Packit |
c32a2d |
int newdir;
|
|
Packit |
c32a2d |
/* skip_tracks includes the previous one. */
|
|
Packit |
c32a2d |
if(skip_tracks) --skip_tracks;
|
|
Packit |
c32a2d |
if(skip_tracks)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug("Skipping this track.");
|
|
Packit |
c32a2d |
continue;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(param.delay > 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
controlled_drain();
|
|
Packit |
c32a2d |
/* One should enable terminal control during that sleeping phase! */
|
|
Packit |
c32a2d |
if(param.verbose > 2) fprintf(stderr, "Note: pausing %i seconds before next track.\n", param.delay);
|
|
Packit |
c32a2d |
#ifdef WIN32
|
|
Packit |
c32a2d |
Sleep(param.delay*1000);
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
sleep(param.delay);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(!APPFLAG(MPG123APP_CONTINUE)) frames_left = param.frame_number;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
debug1("Going to play %s", strcmp(fname, "-") ? fname : "standard input");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(intflag || !open_track(fname))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
/* We need the opportunity to cancel in case of --loop -1 . */
|
|
Packit |
c32a2d |
if(param.term_ctrl) term_control(mh, ao);
|
|
Packit |
c32a2d |
else
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
/* No wait for a second interrupt before we started playing. */
|
|
Packit |
c32a2d |
if(intflag) break;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* We already interrupted this cycle, start fresh with the next one. */
|
|
Packit |
c32a2d |
intflag = FALSE;
|
|
Packit |
c32a2d |
continue;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!param.quiet) fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
if(param.index)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(param.verbose) fprintf(stderr, "indexing...\r");
|
|
Packit |
c32a2d |
mpg123_scan(mh);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
/*
|
|
Packit |
c32a2d |
Only trigger a seek if we do not want to start with the first frame.
|
|
Packit |
c32a2d |
Rationale: Because of libmpg123 sample accuracy, this could cause an unnecessary backwards seek, that even may fail on non-seekable streams.
|
|
Packit |
c32a2d |
For start frame of 0, we are already at the correct position!
|
|
Packit |
c32a2d |
*/
|
|
Packit |
c32a2d |
framenum = 0;
|
|
Packit |
c32a2d |
if(param.start_frame > 0)
|
|
Packit |
c32a2d |
framenum = mpg123_seek_frame(mh, param.start_frame, SEEK_SET);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(APPFLAG(MPG123APP_CONTINUE)) param.start_frame = 0;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(framenum < 0)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
error1("Initial seek failed: %s", mpg123_strerror(mh));
|
|
Packit |
c32a2d |
if(mpg123_errcode(mh) == MPG123_BAD_OUTFORMAT)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(stderr, "%s", "So, you have trouble getting an output format... this is the matrix of currently possible formats:\n");
|
|
Packit |
c32a2d |
print_capabilities(ao, mh);
|
|
Packit |
c32a2d |
fprintf(stderr, "%s", "Somehow the input data and your choices don't allow one of these.\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
mpg123_close(mh);
|
|
Packit |
c32a2d |
continue;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Prinout and xterm title need this, possibly independently. */
|
|
Packit |
c32a2d |
newdir = split_dir_file(fname ? fname : "standard input", &dirname, &filename);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (!param.quiet)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
size_t plpos;
|
|
Packit |
c32a2d |
size_t plfill;
|
|
Packit |
c32a2d |
long plloop;
|
|
Packit |
c32a2d |
plpos = playlist_pos(&plfill, &plloop);
|
|
Packit |
c32a2d |
if(newdir) fprintf(stderr, "Directory: %s\n", dirname);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
/* Reminder about terminal usage. */
|
|
Packit |
c32a2d |
if(param.term_ctrl) term_hint();
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(param.verbose)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(plloop < 0)
|
|
Packit |
c32a2d |
fprintf(stderr, "Repeating endlessly.\n");
|
|
Packit |
c32a2d |
else if(plloop > 1)
|
|
Packit |
c32a2d |
fprintf( stderr, "Repeating %ld %s.\n"
|
|
Packit |
c32a2d |
, plloop-1, plloop > 2 ? "times" : "time" );
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
fprintf( stderr, "Playing MPEG stream %"SIZE_P" of %"SIZE_P": %s ...\n"
|
|
Packit |
c32a2d |
, (size_p)plpos, (size_p)plfill, filename );
|
|
Packit |
c32a2d |
if(htd.icy_name.fill) fprintf(stderr, "ICY-NAME: %s\n", htd.icy_name.p);
|
|
Packit |
c32a2d |
if(htd.icy_url.fill) fprintf(stderr, "ICY-URL: %s\n", htd.icy_url.p);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#if !defined(GENERIC)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
const char *term_type;
|
|
Packit |
c32a2d |
term_type = getenv("TERM");
|
|
Packit |
c32a2d |
if(term_type && param.xterm_title)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!strncmp(term_type,"xterm",5) || !strncmp(term_type,"rxvt",4))
|
|
Packit |
c32a2d |
fprintf(stderr, "\033]0;%s\007", filename);
|
|
Packit |
c32a2d |
else if(!strncmp(term_type,"screen",6))
|
|
Packit |
c32a2d |
fprintf(stderr, "\033k%s\033\\", filename);
|
|
Packit |
c32a2d |
else if(!strncmp(term_type,"iris-ansi",9))
|
|
Packit |
c32a2d |
fprintf(stderr, "\033P1.y %s\033\\\033P3.y%s\033\\", filename, filename);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fflush(stderr); /* Paranoia: will the buffer buffer the escapes? */
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Rethink that SIGINT logic... */
|
|
Packit |
c32a2d |
#if !defined(WIN32) && !defined(GENERIC)
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(!param.term_ctrl)
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
gettimeofday (&start_time, NULL);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
while(!intflag)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
int meta;
|
|
Packit |
c32a2d |
if(param.frame_number > -1)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
debug1("frames left: %li", (long) frames_left);
|
|
Packit |
c32a2d |
if(!frames_left)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(APPFLAG(MPG123APP_CONTINUE)) end_of_files = TRUE;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
break;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(!play_frame()) break;
|
|
Packit |
c32a2d |
if(!param.quiet)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
meta = mpg123_meta_check(mh);
|
|
Packit |
c32a2d |
if(meta & (MPG123_NEW_ID3|MPG123_NEW_ICY))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(meta & MPG123_NEW_ID3) print_id3_tag(mh, param.long_id3, stderr);
|
|
Packit |
c32a2d |
if(meta & MPG123_NEW_ICY) print_icy(mh, stderr);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(!param.term_ctrl) /* Terminal user can query meta data again. */
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
mpg123_meta_free(mh); /* Do not waste memory after delivering. */
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
if(!fresh && param.verbose)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(param.verbose > 1 || !(framenum & 0x7)) print_stat(mh,0,ao,1);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
if(!param.term_ctrl) continue;
|
|
Packit |
c32a2d |
else term_control(mh, ao);
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!param.smooth && !intflag)
|
|
Packit |
c32a2d |
controlled_drain();
|
|
Packit |
c32a2d |
if(param.verbose) print_stat(mh,0,ao,0);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!param.quiet)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
double secs;
|
|
Packit |
c32a2d |
long frank;
|
|
Packit |
c32a2d |
fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
if(mpg123_getstate(mh, MPG123_FRANKENSTEIN, &frank, NULL) == MPG123_OK && frank)
|
|
Packit |
c32a2d |
fprintf(stderr, "This was a Frankenstein track.\n");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
mpg123_position(mh, 0, 0, NULL, NULL, &secs, NULL);
|
|
Packit |
c32a2d |
fprintf(stderr,"[%d:%02d] Decoding of %s finished.\n", (int)(secs / 60), ((int)secs) % 60, filename);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
else if(param.verbose) fprintf(stderr, "\n");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
close_track();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if (intflag)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
if(!skip_or_die(&start_time)) break;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
intflag = FALSE;
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(!param.smooth)
|
|
Packit |
c32a2d |
out123_drop(ao);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(end_of_files) break;
|
|
Packit |
c32a2d |
} /* end of loop over input files */
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
if(APPFLAG(MPG123APP_CONTINUE))
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
continue_msg("CONTINUE");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
/* Free up memory used by playlist */
|
|
Packit |
c32a2d |
if(!param.remote) free_playlist();
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
safe_exit(0); /* That closes output and restores terminal, too. */
|
|
Packit |
c32a2d |
return 0;
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void print_title(FILE *o)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(o, "High Performance MPEG 1.0/2.0/2.5 Audio Player for Layers 1, 2 and 3\n");
|
|
Packit |
c32a2d |
fprintf(o, "\tversion %s; written and copyright by Michael Hipp and others\n", PACKAGE_VERSION);
|
|
Packit |
c32a2d |
fprintf(o, "\tfree software (LGPL) without any warranty but with best wishes\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void usage(int err) /* print syntax & exit */
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
FILE* o = stdout;
|
|
Packit |
c32a2d |
if(err)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
o = stderr;
|
|
Packit |
c32a2d |
fprintf(o, "You made some mistake in program usage... let me briefly remind you:\n\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
print_title(o);
|
|
Packit |
c32a2d |
fprintf(o,"\nusage: %s [option(s)] [file(s) | URL(s) | -]\n", prgName);
|
|
Packit |
c32a2d |
fprintf(o,"supported options [defaults in brackets]:\n");
|
|
Packit |
c32a2d |
fprintf(o," -v increase verbosity level -q quiet (don't print title)\n");
|
|
Packit |
c32a2d |
fprintf(o," -t testmode (no output) -s write to stdout\n");
|
|
Packit |
c32a2d |
fprintf(o," -w f write output as WAV file\n");
|
|
Packit |
c32a2d |
fprintf(o," -k n skip first n frames [0] -n n decode only n frames [all]\n");
|
|
Packit |
c32a2d |
fprintf(o," -c check range violations -y DISABLE resync on errors\n");
|
|
Packit |
c32a2d |
fprintf(o," -b n output buffer: n Kbytes [0] -f n change scalefactor [%li]\n", param.outscale);
|
|
Packit |
c32a2d |
fprintf(o," -r n set/force samplerate [auto]\n");
|
|
Packit |
c32a2d |
fprintf(o," -o m select output module -a d set audio device\n");
|
|
Packit |
c32a2d |
fprintf(o," -2 downsample 1:2 (22 kHz) -4 downsample 1:4 (11 kHz)\n");
|
|
Packit |
c32a2d |
fprintf(o," -d n play every n'th frame only -h n play every frame n times\n");
|
|
Packit |
c32a2d |
fprintf(o," -0 decode channel 0 (left) only -1 decode channel 1 (right) only\n");
|
|
Packit |
c32a2d |
#ifdef NETWORK
|
|
Packit |
c32a2d |
fprintf(o," -m mix both channels (mono) -p p use HTTP proxy p [$HTTP_PROXY]\n");
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
fprintf(o," -m mix both channels (mono)\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_SCHED_SETSCHEDULER
|
|
Packit |
c32a2d |
fprintf(o," -@ f read filenames/URLs from f -T get realtime priority\n");
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
fprintf(o," -@ f read filenames/URLs from f\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," -z shuffle play (with wildcards) -Z random play\n");
|
|
Packit |
c32a2d |
fprintf(o," -u a HTTP authentication string -E f Equalizer, data from file\n");
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
fprintf(o," -C enable control keys --no-gapless not skip junk/padding in mp3s\n");
|
|
Packit |
c32a2d |
#else
|
|
Packit |
c32a2d |
fprintf(o," --no-gapless not skip junk/padding in mp3s\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," -? this help --version print name + version\n");
|
|
Packit |
c32a2d |
fprintf(o,"See the manpage "PACKAGE_NAME"(1) or call %s with --longhelp for more parameters and information.\n", prgName);
|
|
Packit |
c32a2d |
safe_exit(err);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void want_usage(char* arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
usage(0);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void long_usage(int err)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
mpg123_string *enclist;
|
|
Packit |
c32a2d |
FILE* o = stdout;
|
|
Packit |
c32a2d |
if(err)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
o = stderr;
|
|
Packit |
c32a2d |
fprintf(o, "You made some mistake in program usage... let me remind you:\n\n");
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
enclist = audio_enclist();
|
|
Packit |
c32a2d |
print_title(o);
|
|
Packit |
c32a2d |
fprintf(o,"\nusage: %s [option(s)] [file(s) | URL(s) | -]\n", prgName);
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fprintf(o,"\ninput options\n\n");
|
|
Packit |
c32a2d |
fprintf(o," -k <n> --skip <n> skip n frames at beginning\n");
|
|
Packit |
c32a2d |
fprintf(o," --skip-id3v2 skip ID3v2 tags without parsing\n");
|
|
Packit |
c32a2d |
fprintf(o," -n --frames <n> play only <n> frames of every stream\n");
|
|
Packit |
c32a2d |
fprintf(o," --fuzzy Enable fuzzy seeks (guessing byte offsets or using approximate seek points from Xing TOC)\n");
|
|
Packit |
c32a2d |
fprintf(o," -y --no-resync DISABLES resync on error (--resync is deprecated)\n");
|
|
Packit |
c32a2d |
#ifdef NETWORK
|
|
Packit |
c32a2d |
fprintf(o," -p <f> --proxy <f> set WWW proxy\n");
|
|
Packit |
c32a2d |
fprintf(o," -u --auth set auth values for HTTP access\n");
|
|
Packit |
c32a2d |
fprintf(o," --ignore-mime ignore HTTP MIME types (content-type)\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," --no-seekbuffer disable seek buffer\n");
|
|
Packit |
c32a2d |
fprintf(o," -@ <f> --list <f> play songs in playlist <f> (plain list, m3u, pls (shoutcast))\n");
|
|
Packit |
c32a2d |
fprintf(o," -l <n> --listentry <n> play nth title in playlist; show whole playlist for n < 0\n");
|
|
Packit |
c32a2d |
fprintf(o," --continue playlist continuation mode (see man page)\n");
|
|
Packit |
c32a2d |
fprintf(o," --loop <n> loop track(s) <n> times, < 0 means infinite loop (not with --random!)\n");
|
|
Packit |
c32a2d |
fprintf(o," --keep-open (--remote mode only) keep loaded file open after reaching end\n");
|
|
Packit |
c32a2d |
fprintf(o," --timeout <n> Timeout in seconds before declaring a stream dead (if <= 0, wait forever)\n");
|
|
Packit |
c32a2d |
fprintf(o," -z --shuffle shuffle song-list before playing\n");
|
|
Packit |
c32a2d |
fprintf(o," -Z --random full random play\n");
|
|
Packit |
c32a2d |
fprintf(o," --no-icy-meta Do not accept ICY meta data\n");
|
|
Packit |
c32a2d |
fprintf(o," -i --index index / scan through the track before playback\n");
|
|
Packit |
c32a2d |
fprintf(o," --index-size <n> change size of frame index\n");
|
|
Packit |
c32a2d |
fprintf(o," --preframes <n> number of frames to decode in advance after seeking (to keep layer 3 bit reservoir happy)\n");
|
|
Packit |
c32a2d |
fprintf(o," --resync-limit <n> Set number of bytes to search for valid MPEG data; <0 means search whole stream.\n");
|
|
Packit |
c32a2d |
fprintf(o," --streamdump <f> Dump a copy of input data (as read by libmpg123) to given file.\n");
|
|
Packit |
c32a2d |
fprintf(o," --icy-interval <n> Enforce ICY interval in bytes (for playing a stream dump.\n");
|
|
Packit |
c32a2d |
fprintf(o," --ignore-streamlength Ignore header info about length of MPEG streams.");
|
|
Packit |
c32a2d |
fprintf(o,"\noutput/processing options\n\n");
|
|
Packit |
c32a2d |
fprintf(o," -o <o> --output <o> select audio output module\n");
|
|
Packit |
c32a2d |
fprintf(o," --list-modules list the available modules\n");
|
|
Packit |
c32a2d |
fprintf(o," -a <d> --audiodevice <d> select audio device (depending on chosen module)\n");
|
|
Packit |
c32a2d |
fprintf(o," -s --stdout write raw audio to stdout (host native format)\n");
|
|
Packit |
c32a2d |
fprintf(o," -S --STDOUT play AND output stream (not implemented yet)\n");
|
|
Packit |
c32a2d |
fprintf(o," -w <f> --wav <f> write samples as WAV file in <f> (- is stdout)\n");
|
|
Packit |
c32a2d |
fprintf(o," --au <f> write samples as Sun AU file in <f> (- is stdout)\n");
|
|
Packit |
c32a2d |
fprintf(o," --cdr <f> write samples as raw CD audio file in <f> (- is stdout)\n");
|
|
Packit |
c32a2d |
fprintf(o," --reopen force close/open on audiodevice\n");
|
|
Packit |
c32a2d |
#ifdef OPT_MULTI
|
|
Packit |
c32a2d |
fprintf(o," --cpu <string> set cpu optimization\n");
|
|
Packit |
c32a2d |
fprintf(o," --test-cpu list optimizations possible with cpu and exit\n");
|
|
Packit |
c32a2d |
fprintf(o," --list-cpu list builtin optimizations and exit\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef OPT_3DNOW
|
|
Packit |
c32a2d |
fprintf(o," --test-3dnow display result of 3DNow! autodetect and exit (obsoleted by --cpu)\n");
|
|
Packit |
c32a2d |
fprintf(o," --force-3dnow force use of 3DNow! optimized routine (obsoleted by --test-cpu)\n");
|
|
Packit |
c32a2d |
fprintf(o," --no-3dnow force use of floating-pointer routine (obsoleted by --cpu)\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," -g --gain [DEPRECATED] set audio hardware output gain\n");
|
|
Packit |
c32a2d |
fprintf(o," -f <n> --scale <n> scale output samples (soft gain - based on 32768), default=%li)\n", param.outscale);
|
|
Packit |
c32a2d |
fprintf(o," --rva-mix,\n");
|
|
Packit |
c32a2d |
fprintf(o," --rva-radio use RVA2/ReplayGain values for mix/radio mode\n");
|
|
Packit |
c32a2d |
fprintf(o," --rva-album,\n");
|
|
Packit |
c32a2d |
fprintf(o," --rva-audiophile use RVA2/ReplayGain values for album/audiophile mode\n");
|
|
Packit |
c32a2d |
fprintf(o," -0 --left --single0 play only left channel\n");
|
|
Packit |
c32a2d |
fprintf(o," -1 --right --single1 play only right channel\n");
|
|
Packit |
c32a2d |
fprintf(o," -m --mono --mix mix stereo to mono\n");
|
|
Packit |
c32a2d |
fprintf(o," --stereo duplicate mono channel\n");
|
|
Packit |
c32a2d |
fprintf(o," -r --rate force a specific audio output rate\n");
|
|
Packit |
c32a2d |
fprintf(o," -2 --2to1 2:1 downsampling\n");
|
|
Packit |
c32a2d |
fprintf(o," -4 --4to1 4:1 downsampling\n");
|
|
Packit |
c32a2d |
fprintf(o," --pitch <value> set hardware pitch (speedup/down, 0 is neutral; 0.05 is 5%%)\n");
|
|
Packit |
c32a2d |
fprintf(o," --8bit force 8 bit output\n");
|
|
Packit |
c32a2d |
fprintf(o," --float force floating point output (internal precision)\n");
|
|
Packit |
c32a2d |
fprintf(o," -e <c> --encoding <c> force a specific encoding (%s)\n"
|
|
Packit |
c32a2d |
, enclist != NULL ? enclist->p : "OOM!");
|
|
Packit |
c32a2d |
fprintf(o," -d n --doublespeed n play only every nth frame\n");
|
|
Packit |
c32a2d |
fprintf(o," -h n --halfspeed n play every frame n times\n");
|
|
Packit |
c32a2d |
fprintf(o," --equalizer exp.: scales freq. bands acrd. to 'equalizer.dat'\n");
|
|
Packit |
c32a2d |
fprintf(o," --gapless remove padding/junk on mp3s (best with Lame tag)\n");
|
|
Packit |
c32a2d |
fprintf(o," This is on by default when libmpg123 supports it.\n");
|
|
Packit |
c32a2d |
fprintf(o," --no-gapless disable gapless mode, not remove padding/junk\n");
|
|
Packit |
c32a2d |
fprintf(o," --no-infoframe disable parsing of Xing/Lame/VBR/Info frame\n");
|
|
Packit |
c32a2d |
fprintf(o," -D n --delay n insert a delay of n seconds before each track\n");
|
|
Packit |
c32a2d |
fprintf(o," -o h --headphones (aix/hp/sun) output on headphones\n");
|
|
Packit |
c32a2d |
fprintf(o," -o s --speaker (aix/hp/sun) output on speaker\n");
|
|
Packit |
c32a2d |
fprintf(o," -o l --lineout (aix/hp/sun) output to lineout\n");
|
|
Packit |
c32a2d |
#ifndef NOXFERMEM
|
|
Packit |
c32a2d |
fprintf(o," -b <n> --buffer <n> set play buffer (\"output cache\")\n");
|
|
Packit |
c32a2d |
fprintf(o," --preload <value> fraction of buffer to fill before playback\n");
|
|
Packit |
c32a2d |
fprintf(o," --smooth keep buffer over track boundaries\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," --devbuffer <s> set device buffer in seconds; <= 0 means default\n");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fprintf(o,"\nmisc options\n\n");
|
|
Packit |
c32a2d |
fprintf(o," -t --test only decode, no output (benchmark)\n");
|
|
Packit |
c32a2d |
fprintf(o," -c --check count and display clipped samples\n");
|
|
Packit |
c32a2d |
fprintf(o," -v[*] --verbose increase verboselevel\n");
|
|
Packit |
c32a2d |
fprintf(o," -q --quiet quiet mode\n");
|
|
Packit |
c32a2d |
#ifdef HAVE_TERMIOS
|
|
Packit |
c32a2d |
fprintf(o," -C --control enable terminal control keys (else auto detect)\n");
|
|
Packit |
c32a2d |
fprintf(o," --no-control disable terminal control keys (disable auto detect)\n");
|
|
Packit |
c32a2d |
fprintf(o," --ctrlusr1 <c> control key (characer) to map to SIGUSR1\n");
|
|
Packit |
c32a2d |
fprintf(o," (default is for stop/start)\n");
|
|
Packit |
c32a2d |
fprintf(o," --ctrlusr2 <c> control key (characer) to map to SIGUSR2\n");
|
|
Packit |
c32a2d |
fprintf(o," (default is for next track)\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifndef GENERIC
|
|
Packit |
c32a2d |
fprintf(o," --title set terminal title to filename\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," --name <n> set instance name (used in various places)\n");
|
|
Packit |
c32a2d |
fprintf(o," --long-tag spacy id3 display with every item on a separate line\n");
|
|
Packit |
c32a2d |
fprintf(o," --lyrics show lyrics (from ID3v2 USLT frame)\n");
|
|
Packit |
c32a2d |
fprintf(o," --utf8 Regardless of environment, print metadata in UTF-8.\n");
|
|
Packit |
c32a2d |
fprintf(o," -R --remote generic remote interface\n");
|
|
Packit |
c32a2d |
fprintf(o," --remote-err force use of stderr for generic remote interface\n");
|
|
Packit |
c32a2d |
#ifdef FIFO
|
|
Packit |
c32a2d |
fprintf(o," --fifo <path> open a FIFO at <path> for commands instead of stdin\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_SETPRIORITY
|
|
Packit |
c32a2d |
fprintf(o," --aggressive tries to get higher priority (nice)\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#if defined (HAVE_SCHED_SETSCHEDULER) || defined (HAVE_WINDOWS_H)
|
|
Packit |
c32a2d |
fprintf(o," -T --realtime tries to get realtime priority\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
#ifdef HAVE_WINDOWS_H
|
|
Packit |
c32a2d |
fprintf(o," --priority <n> use specified process priority\n");
|
|
Packit |
c32a2d |
fprintf(o," accepts -2 to 3 as integer arguments\n");
|
|
Packit |
c32a2d |
fprintf(o," -2 as idle, 0 as normal and 3 as realtime.\n");
|
|
Packit |
c32a2d |
#endif
|
|
Packit |
c32a2d |
fprintf(o," -? --help give compact help\n");
|
|
Packit |
c32a2d |
fprintf(o," --longhelp give this long help listing\n");
|
|
Packit |
c32a2d |
fprintf(o," --version give name / version string\n");
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
fprintf(o,"\nSee the manpage "PACKAGE_NAME"(1) for more information.\n");
|
|
Packit |
c32a2d |
mpg123_free_string(enclist);
|
|
Packit |
c32a2d |
free(enclist);
|
|
Packit |
c32a2d |
safe_exit(err);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void want_long_usage(char* arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
long_usage(0);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
static void give_version(char* arg)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf(stdout, PACKAGE_NAME" "PACKAGE_VERSION"\n");
|
|
Packit |
c32a2d |
safe_exit(0);
|
|
Packit |
c32a2d |
}
|
|
Packit |
c32a2d |
|
|
Packit |
c32a2d |
void continue_msg(const char *name)
|
|
Packit |
c32a2d |
{
|
|
Packit |
c32a2d |
fprintf( aux_out, "\n[%s] track %"SIZE_P" frame %"OFF_P"\n", name
|
|
Packit |
c32a2d |
, (size_p)playlist_pos(NULL, NULL), (off_p)framenum );
|
|
Packit |
c32a2d |
}
|