Commit 887593ce authored by Led's avatar Led

0.11.0-pre1

parent 70d6e3ee
......@@ -4,6 +4,7 @@ wave File Support -> normalperson
setuid patch -> Nagilum
'next' and 'previous' patch -> Niklas Hofer
command.c cleanup -> mackstann
replayGain -> AliasMrJones
libid3tag and libmad copyrighted by Robert Leslie, http://www.underbit.com/products/mad
mp4ff copyrighted by M. Bakker, Ahead Software AG, http://www.nero.com
ver 0.10.4 (2004/5/26)
1) Fix configure problems on OpenBSD with langinfo and iconv
2) Fix an infinte loop when writing to an interface and it has expired
3) Fix a segfault in decoding flac's
4) Ingore CRC stuff in mp3's since some encoders did not compute the CRC correctly
5) Fix a segfault in processing faulty mp4 metadata
ver 0.10.3 (2004/4/2)
1) Fix a segfault when a blanck line is sent from a client
2) Fix for loading playlists on platforms where char is unsigned
......
......@@ -76,7 +76,7 @@ Run
$ mpd <port> <mp3 directory> <playlist directory> <mpd log> <mpd err>
example where mpd executable is in mpd-x.x.x directory:
$ mpd-x.x.x/mpd 2100 mp3 playlists mpd.log mpd.err
$ mpd-x.x.x/mpd 6600 mp3 playlists mpd.log mpd.err
Note: The first time you run mpd, it will "explore" your mp3 directory for
mp3's.
......
......@@ -84,6 +84,10 @@ ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBMIKMOD_CFLAGS = @LIBMIKMOD_CFLAGS@
LIBMIKMOD_CONFIG = @LIBMIKMOD_CONFIG@
LIBMIKMOD_LDADD = @LIBMIKMOD_LDADD@
LIBMIKMOD_LIBS = @LIBMIKMOD_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
......
1) put some sort of error reporting for streaming/inputStream!
2) Fix charset errors so they don't goto stderr/out
Post-1.0
--------
1) crosslink "list" stuff, for example, artists are crosslinked to alubms and
vice versa, this way you can do list album artists or list artist albums, this
will make life easier when we add genre and other metadata
2) rewrite linked list impelmentation to be more flexible
a) remove "key" stuff
b) allow assigning a compare function for a list
......@@ -3,6 +3,9 @@
/* Define if alsa support is present */
#undef HAVE_ALSA
/* Define to play audio */
#undef HAVE_AUDIO
/* Define for audiofile support */
#undef HAVE_AUDIOFILE
......@@ -64,6 +67,9 @@
/* Define to 1 if you have the <memory.h> header file. */
#undef HAVE_MEMORY_H
/* Define for mikmod support */
#undef HAVE_MIKMOD
/* Define to 1 if the system has the type `mp4AudioSpecificConfig'. */
#undef HAVE_MP4AUDIOSPECIFICCONFIG
......
#! /bin/sh
# Configuration validation subroutine script.
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
# 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
# 2000, 2001, 2002 Free Software Foundation, Inc.
timestamp='2003-01-03'
timestamp='2002-09-05'
# This file is (in principle) common to ALL GNU software.
# The presence of a machine in this file suggests that SOME GNU software
......@@ -118,7 +118,7 @@ esac
# Here we must recognize all the valid KERNEL-OS combinations.
maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
case $maybe_os in
nto-qnx* | linux-gnu* | freebsd*-gnu* | netbsd*-gnu* | storm-chaos* | os2-emx* | rtmk-nova*)
nto-qnx* | linux-gnu* | freebsd*-gnu* | storm-chaos* | os2-emx* | windows32-* | rtmk-nova*)
os=-$maybe_os
basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
;;
......@@ -245,19 +245,16 @@ case $basic_machine in
| mips64vr4300 | mips64vr4300el \
| mips64vr5000 | mips64vr5000el \
| mipsisa32 | mipsisa32el \
| mipsisa32r2 | mipsisa32r2el \
| mipsisa64 | mipsisa64el \
| mipsisa64sb1 | mipsisa64sb1el \
| mipsisa64sr71k | mipsisa64sr71kel \
| mipstx39 | mipstx39el \
| mn10200 | mn10300 \
| msp430 \
| ns16k | ns32k \
| openrisc | or32 \
| pdp10 | pdp11 | pj | pjl \
| powerpc | powerpc64 | powerpc64le | powerpcle | ppcbe \
| pyramid \
| s390 | s390x \
| sh | sh[1234] | sh3e | sh[34]eb | shbe | shle | sh[1234]le | sh3ele \
| sh64 | sh64le \
| sparc | sparc64 | sparc86x | sparclet | sparclite | sparcv9 | sparcv9b \
......@@ -318,19 +315,16 @@ case $basic_machine in
| mips64vr4300-* | mips64vr4300el-* \
| mips64vr5000-* | mips64vr5000el-* \
| mipsisa32-* | mipsisa32el-* \
| mipsisa32r2-* | mipsisa32r2el-* \
| mipsisa64-* | mipsisa64el-* \
| mipsisa64sb1-* | mipsisa64sb1el-* \
| mipsisa64sr71k-* | mipsisa64sr71kel-* \
| mipstx39-* | mipstx39el-* \
| msp430-* \
| none-* | np1-* | nv1-* | ns16k-* | ns32k-* \
| mipstx39 | mipstx39el \
| none-* | np1-* | ns16k-* | ns32k-* \
| orion-* \
| pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
| powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* | ppcbe-* \
| pyramid-* \
| romp-* | rs6000-* \
| s390-* | s390x-* \
| sh-* | sh[1234]-* | sh3e-* | sh[34]eb-* | shbe-* \
| shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
| sparc-* | sparc64-* | sparc86x-* | sparclet-* | sparclite-* \
......@@ -373,6 +367,9 @@ case $basic_machine in
basic_machine=a29k-none
os=-bsd
;;
amd64-*)
basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
;;
amdahl)
basic_machine=580-amdahl
os=-sysv
......@@ -722,10 +719,6 @@ case $basic_machine in
np1)
basic_machine=np1-gould
;;
nv1)
basic_machine=nv1-cray
os=-unicosmp
;;
nsr-tandem)
basic_machine=nsr-tandem
;;
......@@ -822,6 +815,12 @@ case $basic_machine in
rtpc | rtpc-*)
basic_machine=romp-ibm
;;
s390 | s390-*)
basic_machine=s390-ibm
;;
s390x | s390x-*)
basic_machine=s390x-ibm
;;
sa29200)
basic_machine=a29k-amd
os=-udi
......@@ -905,6 +904,10 @@ case $basic_machine in
basic_machine=i386-sequent
os=-dynix
;;
t3d)
basic_machine=alpha-cray
os=-unicos
;;
t3e)
basic_machine=alphaev5-cray
os=-unicos
......@@ -977,6 +980,10 @@ case $basic_machine in
basic_machine=hppa1.1-winbond
os=-proelf
;;
windows32)
basic_machine=i386-pc
os=-windows32-msvcrt
;;
xps | xps100)
basic_machine=xps100-honeywell
;;
......@@ -1109,12 +1116,11 @@ case $os in
| -chorusos* | -chorusrdb* \
| -cygwin* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
| -mingw32* | -linux-gnu* | -uxpv* | -beos* | -mpeix* | -udk* \
| -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
| -interix* | -uwin* | -rhapsody* | -darwin* | -opened* \
| -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
| -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
| -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
| -powermax* | -dnix* | -microbsd*)
| -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* | -powermax*)
# Remember, each alternative MUST END IN *, to match a version number.
;;
-qnx*)
......@@ -1126,10 +1132,8 @@ case $os in
;;
esac
;;
-nto-qnx*)
;;
-nto*)
os=`echo $os | sed -e 's|nto|nto-qnx|'`
os=-nto-qnx
;;
-sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
| -windows* | -osx | -abug | -netware* | -os9* | -beos* \
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -2,7 +2,7 @@ dnl AC_INIT(src/main.c)
dnl AM_INIT_AUTOMAKE(mpd, 0.10.0)
AC_PREREQ(2.52)
AC_INIT(mpd, 0.10.4, shank@mercury.chem.pitt.edu)
AC_INIT(mpd, 0.11.0, shank@mercury.chem.pitt.edu)
AM_INIT_AUTOMAKE($PACKAGE_NAME, $PACKAGE_VERSION)
dnl MAD wants this stuff
......@@ -21,22 +21,28 @@ AC_SUBST(MPD_CFLAGS)
AC_PROG_CC
AC_PROG_INSTALL
AC_PROG_LIBTOOL
AC_PROG_MAKE_SET
AM_CONFIG_HEADER(config.h)
MPD_CFLAGS="-Wall"
MPD_CFLAGS=""
if test x$CC = xgcc; then
MPD_CFLAGS="-Wall"
fi
MPD_LIBS=""
AC_ARG_ENABLE(audio,[ --disable-audio disable support for playing],,enable_ao=yes)
AC_ARG_ENABLE(iconv,[ --disable-iconv disable iconv support],,enable_iconv=yes)
AC_ARG_ENABLE(ipv6,[ --disable-ipv6 disable IPv6 support],,enable_ipv6=yes)
AC_ARG_ENABLE(alsa,[ --disable-alsa disable Alsa Mixer support],,enable_alsa=yes)
AC_ARG_ENABLE(alsa,[ --disable-alsa disable ALSA Mixer support],,enable_alsa=yes)
AC_ARG_ENABLE(ogg,[ --disable-ogg disable ogg support],,enable_ogg=yes)
AC_ARG_ENABLE(flac,[ --disable-flac disable flac support],,enable_flac=yes)
AC_ARG_ENABLE(mp3,[ --disable-mp3 disable mp3 support],,enable_mp3=yes)
AC_ARG_ENABLE(aac,[ --disable-aac disable AAC support],,enable_aac=yes)
AC_ARG_ENABLE(audiofile,[ --disable-audiofile disable audiofile support, disables wave support],,enable_audiofile=yes)
AC_ARG_ENABLE(mpd_mad,[ --enable-mpd-mad use mpd libmad],use_mpd_mad=yes,)
AC_ARG_ENABLE(mod,[ --disable-mod disable MOD support],,enable_mod=yes)
AC_ARG_ENABLE(id3,[ --disable-id3 disable id3 support],,enable_id3=yes)
AC_ARG_ENABLE(mpd_mad,[ --enable-mpd-mad use mpd libmad],use_mpd_mad=yes,)
AC_ARG_ENABLE(mpd_id3tag,[ --enable-mpd-id3tag use mpd libid3tag],use_mpd_id3tag=yes,)
AC_ARG_WITH(iconv,[ --with-iconv=PFX Prefix where iconv is installed (optional)], iconv_prefix="$withval", iconv_prefix="")
......@@ -69,6 +75,8 @@ AC_CHECK_LIB(nsl,gethostbyname,MPD_LIBS="$MPD_LIBS -lnsl",)
AC_CHECK_LIB(m,exp,MPD_LIBS="$MPD_LIBS -lm",)
dnl doesn't work for systems that don't have CODESET like OpenBSD
dnl AC_CHECK_HEADER(langinfo.h,[enable_langinfo=yes;AC_DEFINE(HAVE_LANGINFO,1,[Define if nl_langinfo.h is present])],enable_langinfo=no)
AM_LANGINFO_CODESET
AC_CHECK_HEADER(locale.h,[enable_locale=yes;AC_DEFINE(HAVE_LOCALE,1,[Define if locale.h is present])],enable_locale=no)
......@@ -91,7 +99,11 @@ AP_maGiC_VALUE
)
fi
XIPH_PATH_AO(MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS",AC_MSG_ERROR(Must have libao installed!!!))
if test x$enable_ao = xyes; then
XIPH_PATH_AO(MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS",AC_MSG_ERROR(Must have libao installed!!!))
AC_DEFINE(HAVE_AUDIO, 1, [Define to play audio])
fi
AC_CHECK_HEADER(sys/soundcard.h,enable_oss=yes,[AC_MSG_WARN(Soundcard headers not found -- disabling OSS mixer);enable_oss=no;AC_DEFINE(NO_OSS_MIXER,1,[Define to disable OSS mixer support])])
if test x$enable_alsa = xyes; then
......@@ -462,6 +474,14 @@ if test x$enable_audiofile = xyes; then
AC_DEFINE(HAVE_AUDIOFILE,1,[Define for audiofile support])
fi
if test x$enable_mod = xyes; then
AM_PATH_LIBMIKMOD(3.1.7, MPD_CFLAGS="$MPD_CFLAGS $LIBMIKMOD_CFLAGS"
MPD_LIBS="$MPD_LIBS $LIBMIKMOD_LIBS", enable_mod=no)
if test x$enable_mod = xyes; then
AC_DEFINE(HAVE_MIKMOD, 1, [Define for mikmod support])
fi
fi
AC_OUTPUT(src/mp4ff/Makefile doc/Makefile src/Makefile Makefile )
echo ""
......@@ -475,9 +495,9 @@ else
fi
if test x$enable_alsa = xyes; then
echo "Alsa mixer support ............enabled"
echo "ALSA mixer support ............enabled"
else
echo "Alsa mixer support ............disabled"
echo "ALSA mixer support ............disabled"
fi
echo ""
......@@ -502,6 +522,12 @@ fi
echo ""
echo "Audio Format Support:"
if test x$enable_ao = xyes; then
echo "Playing audio .................enabled"
else
echo "Playing audio .................disabled"
fi
if test x$enable_id3 = xyes; then
echo "ID3 tag support ...............enabled"
if test x$use_mpd_id3tag = xyes; then
......@@ -548,6 +574,12 @@ else
echo "MP4/AAC support ...............disabled"
fi
if test x$enable_mod = xyes; then
echo "MOD support ...................enabled"
else
echo "MOD support ...................disabled"
fi
echo ""
echo "##########################################"
echo ""
......
......@@ -106,8 +106,9 @@ playlist
displays the current playlist
NOTE: do not use this, instead use 'playlistinfo'
playlistinfo
displays information about the current playlist
playlistinfo <int song>
displays list of songs in the playlist
_song_ is optional and species a single song to displa info for
previous
plays previous song in playlist
......@@ -125,7 +126,8 @@ save <string name>
saves the current playlist to _name_.m3u in the playlist directory
search <string type> <string what>
same as "find" but searches for any song that contain _what_
searches for any song that contain _what_
_type_ can be "title","artist","album", or "filename"
search is not case sensitive
seek <int song> <int time>
......@@ -162,6 +164,7 @@ status
bitrate: <int bitrate> (instantaneous bitrate in kbps)
xfade: <int seconds> (crossfade in seconds)
audio: <int sampleRate>:<int bits>:<int channels>
updatings_db: <int job id>
error: if there is an error, returns message here
stop
......@@ -171,9 +174,17 @@ swap <int song1> <int song2>
swap positions of _song1_ and _song2_
increments playlist version by 1
update
update <string path>
searches mp3 directory for new music and removes old music from the db
_path_ is an optional argument that maybe a particular directory or
song/file to update.
returned:
updating_db: <int job id>
where job id, is the job id requested for your update, and is displayed
in status, while the requested update is happening
increments playlist version by 1
NOTE: to update a number of paths/songs at once, use command_list,
it will be much more faster/effecient
volume <int change>
change volume by amount _change_
......
......@@ -84,6 +84,10 @@ ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBMIKMOD_CFLAGS = @LIBMIKMOD_CFLAGS@
LIBMIKMOD_CONFIG = @LIBMIKMOD_CONFIG@
LIBMIKMOD_LDADD = @LIBMIKMOD_LDADD@
LIBMIKMOD_LIBS = @LIBMIKMOD_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
......
......@@ -45,7 +45,7 @@ Below are a list of parameters that can be specified in the config file. Each l
parameter "value"
.TP
.B port <port>
This specifies the port that MPD listens on. This parameter is required. This is typically 2100.
This specifies the port that MPD listens on. This parameter is required. This is typically 6600.
.TP
.B music_directory <directory>
This specifies the directory where music is located. This parameter is required. The directory path should be an absolute path.
......@@ -155,7 +155,7 @@ Below is an example config file. (Note: '#' at the beginning of a line denotes a
.br
# required
.br
port "2100"
port "6600"
.br
music_directory "~/mp3"
.br
......
......@@ -4,7 +4,7 @@
########## REQUIRED ###############
port "2100"
port "6600"
music_directory "~/music"
playlist_directory "~/.mpd/playlists"
log_file "~/.mpd/mpd.log"
......@@ -97,7 +97,7 @@ error_file "~/.mpd/mpd.error"
########### MISC OPTIONS #################
#max_playlist_length "4096"
#max_playlist_length "16384"
#connection_timeout "60"
#max_connections "5"
#max_command_list_size "2048"
......
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR) $(MP4FF_SUBDIR)
mpd_inputPlugins = inputPlugins/mp3_plugin.c inputPlugins/ogg_plugin.c \
inputPlugins/flac_plugin.c inputPlugins/audiofile_plugin.c \
inputPlugins/mp4_plugin.c inputPlugins/aac_plugin.c \
inputPlugins/mod_plugin.c
mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
song.h list.h directory.h tables.h utils.h path.h mp3_decode.h \
tag.h player.h listen.h conf.h ogg_decode.h volume.h flac_decode.h \
song.h list.h directory.h tables.h utils.h path.h \
tag.h player.h listen.h conf.h volume.h \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.h \
audiofile_decode.h charConv.h permission.h mpd_types.h pcm_utils.h \
mp4_decode.h aac_decode.h
charConv.h permission.h mpd_types.h pcm_utils.h \
signal_check.h utf8.h inputStream.h \
outputBuffer.h replayGain.h inputStream_file.h inputStream_http.h \
inputPlugin.h
mpd_SOURCES = main.c buffer2array.c interface.c command.c playlist.c ls.c \
song.c list.c directory.c tables.c utils.c path.c mp3_decode.c \
tag.c player.c listen.c conf.c ogg_decode.c volume.c flac_decode.c \
song.c list.c directory.c tables.c utils.c path.c \
tag.c player.c listen.c conf.c volume.c \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
audiofile_decode.c charConv.c permission.c pcm_utils.c mp4_decode.c \
aac_decode.c $(mpd_headers)
charConv.c permission.c pcm_utils.c \
signal_check.c utf8.c inputStream.c outputBuffer.c \
replayGain.c inputStream_file.c inputStream_http.c inputPlugin.c \
$(mpd_headers) $(mpd_inputPlugins)
mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
......
......@@ -25,15 +25,28 @@
#include <assert.h>
#include <signal.h>
int audio_write_size;
#ifdef HAVE_AUDIO
#include <ao/ao.h>
int audio_ao_driver_id;
ao_option * audio_ao_options;
static int audio_write_size;
AudioFormat audio_format;
ao_device * audio_device = NULL;
static int audio_ao_driver_id;
static ao_option * audio_ao_options;
static AudioFormat audio_format;
static ao_device * audio_device = NULL;
#endif
static AudioFormat * audio_configFormat = NULL;
static void copyAudioFormat(AudioFormat * dest, AudioFormat * src) {
dest->sampleRate = src->sampleRate;
dest->bits = src->bits;
dest->channels = src->channels;
}
void initAudioDriver() {
#ifdef HAVE_AUDIO
ao_info * ai;
char * dup;
char * stk1;
......@@ -49,7 +62,7 @@ void initAudioDriver() {
if (*test!='\0') {
ERROR("\"%s\" is not a valid write size",
(getConf())[CONF_AUDIO_WRITE_SIZE]);
exit(-1);
exit(EXIT_FAILURE);
}
audio_ao_options = NULL;
......@@ -62,13 +75,13 @@ void initAudioDriver() {
ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) {
ERROR("\"%s\" is not a valid ao driver\n",
(getConf())[CONF_AO_DRIVER]);
exit(-1);
exit(EXIT_FAILURE);
}
if((ai = ao_driver_info(audio_ao_driver_id))==NULL) {
ERROR("problems getting ao_driver_info\n");
ERROR("you may not have permission to the audio device\n");
exit(-1);
exit(EXIT_FAILURE);
}
dup = strdup((getConf())[CONF_AO_DRIVER_OPTIONS]);
......@@ -81,7 +94,7 @@ void initAudioDriver() {
if(!key) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(-1);
exit(EXIT_FAILURE);
}
/*found = 0;
for(i=0;i<ai->option_count;i++) {
......@@ -94,52 +107,131 @@ void initAudioDriver() {
ERROR("\"%s\" is not an option for "
"\"%s\" ao driver\n",key,
ai->short_name);
exit(-1);
exit(EXIT_FAILURE);
}*/
value = strtok_r(NULL,"",&stk2);
if(!value) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(-1);
exit(EXIT_FAILURE);
}
ao_append_option(&audio_ao_options,key,value);
n1 = strtok_r(NULL,";",&stk1);
}
}
free(dup);
#endif
}
void getOutputAudioFormat(AudioFormat * inAudioFormat,
AudioFormat * outAudioFormat)
{
if(audio_configFormat) {
copyAudioFormat(outAudioFormat,audio_configFormat);
}
else copyAudioFormat(outAudioFormat,inAudioFormat);
}
void initAudioConfig() {
char * conf = getConf()[CONF_AUDIO_OUTPUT_FORMAT];
char * test;
if(NULL == conf) return;
audio_configFormat = malloc(sizeof(AudioFormat));
memset(audio_configFormat,0,sizeof(AudioFormat));
audio_configFormat->sampleRate = strtol(conf,&test,10);
if(*test!=':') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
}
/*switch(audio_configFormat->sampleRate) {
case 48000:
case 44100:
case 32000:
case 16000:
break;
default:
ERROR("sample rate %i can not be used for audio output\n",
(int)audio_configFormat->sampleRate);
exit(EXIT_FAILURE);
}*/
if(audio_configFormat->sampleRate <= 0) {
ERROR("sample rate %i is not >= 0\n",
(int)audio_configFormat->sampleRate);
exit(EXIT_FAILURE);
}
audio_configFormat->bits = strtol(test+1,&test,10);
if(*test!=':') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
}
switch(audio_configFormat->bits) {
case 16:
break;
default:
ERROR("bits %i can not be used for audio output\n",
(int)audio_configFormat->bits);
exit(EXIT_FAILURE);
}
audio_configFormat->channels = strtol(test+1,&test,10);
if(*test!='\0') {
ERROR("error parsing audio output format: %s\n",conf);
exit(EXIT_FAILURE);
}
switch(audio_configFormat->channels) {
case 2:
break;
default:
ERROR("channels %i can not be used for audio output\n",
(int)audio_configFormat->channels);
exit(EXIT_FAILURE);
}
}
void finishAudioConfig() {
if(audio_configFormat) free(audio_configFormat);
}
void finishAudioDriver() {
#ifdef HAVE_AUDIO
ao_free_options(audio_ao_options);
ao_shutdown();
#endif
}
int isCurrentAudioFormat(AudioFormat * audioFormat) {
#ifdef HAVE_AUDIO
if(!audio_device || !audioFormat) return 0;
if(audio_format.bits!=audioFormat->bits ||
audio_format.sampleRate!=audioFormat->sampleRate ||
audio_format.channels!=audioFormat->channels)
{
return 0;
}
if(memcmp(audioFormat,&audio_format,sizeof(AudioFormat)) != 0) return 0;
#endif
return 1;
}
int initAudio(AudioFormat * audioFormat) {
int openAudioDevice(AudioFormat * audioFormat) {
#ifdef HAVE_AUDIO
ao_sample_format format;
if(audio_device && !isCurrentAudioFormat(audioFormat)) {
finishAudio();
closeAudioDevice();
}
if(!audio_device) {
if(audioFormat) {
audio_format.bits = audioFormat->bits;
audio_format.sampleRate = audioFormat->sampleRate;
audio_format.channels = audioFormat->channels;
copyAudioFormat(&audio_format,audioFormat);
}
format.bits = audio_format.bits;
......@@ -154,12 +246,13 @@ int initAudio(AudioFormat * audioFormat) {
if(audio_device==NULL) return -1;
}
#endif
return 0;
}
int playAudio(char * playChunk, int size) {
#ifdef HAVE_AUDIO
int send;
if(audio_device==NULL) {
......@@ -173,7 +266,7 @@ int playAudio(char * playChunk, int size) {
if(ao_play(audio_device,playChunk,send)==0) {
audioError();
ERROR("closing audio device due to write error\n");
finishAudio();
closeAudioDevice();
return -1;
}
......@@ -181,20 +274,23 @@ int playAudio(char * playChunk, int size) {
size-=send;
}
#endif
return 0;
}
void finishAudio() {
void closeAudioDevice() {
#ifdef HAVE_AUDIO
if(audio_device) {
blockSignals();
ao_close(audio_device);
audio_device = NULL;
unblockSignals();
}
#endif
}
void audioError() {
ERROR("Error opening audio device\n");
#ifdef HAVE_AUDIO
if(errno==AO_ENOTLIVE) {
ERROR("not a live ao device\n");
}
......@@ -204,4 +300,6 @@ void audioError() {
else if(errno==AO_EBADOPTION) {
ERROR("bad driver option\n");
}
#endif
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -24,31 +24,34 @@
#include "mpd_types.h"
#include <stdio.h>
#include <ao/ao.h>
#define AUDIO_AO_DRIVER_DEFAULT "default"
typedef struct _AudioFormat {
mpd_sint8 channels;
mpd_uint32 sampleRate;
mpd_sint8 bits;
volatile mpd_sint8 channels;
volatile mpd_uint32 sampleRate;
volatile mpd_sint8 bits;
} AudioFormat;
extern int audio_ao_driver_id;
extern ao_option * audio_ao_options;
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
void initAudioConfig();
void finishAudioConfig();
void initAudioDriver();
void finishAudioDriver();
int initAudio(AudioFormat * audioFormat);
int openAudioDevice(AudioFormat * audioFormat);
int playAudio(char * playChunk,int size);
void finishAudio();
void closeAudioDevice();
void audioError();
int isCurrentAudioFormat(AudioFormat * audioFormat);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -120,3 +120,4 @@ void freeArgArray(char ** array, int argArrayLength) {
}
free(array);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -26,3 +26,4 @@ int buffer2array(char * buffer, char *** array);
void freeArgArray(char ** array, int argArrayLength);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -17,6 +17,8 @@
*/
#include "charConv.h"
#include "mpd_types.h"
#include "utf8.h"
#include <stdlib.h>
#include <errno.h>
......@@ -25,14 +27,21 @@
#ifdef HAVE_ICONV
#include <iconv.h>
iconv_t char_conv_iconv;
#endif
char * char_conv_to = NULL;
char * char_conv_from = NULL;
#endif
mpd_sint8 char_conv_same = 0;
mpd_sint8 char_conv_use_iconv = 0;
/* 1 is to use latin1ToUtf8
0 is not to use latin1/utf8 converter
-1 is to use utf8ToLatin1*/
mpd_sint8 char_conv_latin1ToUtf8 = 0;
#define BUFFER_SIZE 1024
int setCharSetConversion(char * to, char * from) {
#ifdef HAVE_ICONV
if(char_conv_to && strcmp(to,char_conv_to)==0 &&
char_conv_from && strcmp(from,char_conv_from)==0)
{
......@@ -41,60 +50,101 @@ int setCharSetConversion(char * to, char * from) {
closeCharSetConversion();
if(0==strcmp(to,from)) {
char_conv_same = 1;
char_conv_to = strdup(to);
char_conv_from = strdup(from);
return 0;
}
if(strcmp(to,"UTF-8")==0 && strcmp(from,"ISO-8859-1")==0) {
char_conv_latin1ToUtf8 = 1;
}
else if(strcmp(to,"ISO-8859-1")==0 && strcmp(from,"UTF-8")==0) {
char_conv_latin1ToUtf8 = -1;
}
if(char_conv_latin1ToUtf8!=0) {
char_conv_to = strdup(to);
char_conv_from = strdup(from);
return 0;
}
#ifdef HAVE_ICONV
if((char_conv_iconv = iconv_open(to,from))==(iconv_t)(-1)) return -1;
char_conv_to = strdup(to);
char_conv_from = strdup(from);
char_conv_use_iconv = 1;
return 0;
#endif
return -1;
}
char * convStrDup(char * string) {
#ifdef HAVE_ICONV
char buffer[BUFFER_SIZE];
size_t inleft = strlen(string);
char * ret;
size_t outleft;
size_t retlen = 0;
size_t err;
char * bufferPtr;
if(!char_conv_to) return NULL;
ret = malloc(1);
ret[0] = '\0';
if(char_conv_same) return strdup(string);
while(inleft) {
bufferPtr = buffer;
outleft = BUFFER_SIZE;
err = iconv(char_conv_iconv,&string,&inleft,&bufferPtr,
#ifdef HAVE_ICONV
if(char_conv_use_iconv) {
char buffer[BUFFER_SIZE];
size_t inleft = strlen(string);
char * ret;
size_t outleft;
size_t retlen = 0;
size_t err;
char * bufferPtr;
ret = malloc(1);
ret[0] = '\0';
while(inleft) {
bufferPtr = buffer;
outleft = BUFFER_SIZE;
err = iconv(char_conv_iconv,&string,&inleft,&bufferPtr,
&outleft);
if(outleft==BUFFER_SIZE || (err<0 && errno!=E2BIG)) {
free(ret);
return NULL;
if(outleft==BUFFER_SIZE || (err<0 && errno!=E2BIG)) {
free(ret);
return NULL;
}
ret = realloc(ret,retlen+BUFFER_SIZE-outleft+1);
memcpy(ret+retlen,buffer,BUFFER_SIZE-outleft);
retlen+=BUFFER_SIZE-outleft;
ret[retlen] = '\0';
}
ret = realloc(ret,retlen+BUFFER_SIZE-outleft+1);
memcpy(ret+retlen,buffer,BUFFER_SIZE-outleft);
retlen+=BUFFER_SIZE-outleft;
ret[retlen] = '\0';
return ret;
}
return ret;
#endif
switch(char_conv_latin1ToUtf8) {
case 1:
return latin1StrToUtf8Dup(string);
break;
case -1:
return utf8StrToLatin1Dup(string);
break;
}
return NULL;
}
void closeCharSetConversion() {
#ifdef HAVE_ICONV
if(char_conv_to) {
iconv_close(char_conv_iconv);
#ifdef HAVE_ICONV
if(char_conv_use_iconv) iconv_close(char_conv_iconv);
#endif
free(char_conv_to);
free(char_conv_from);
char_conv_to = NULL;
char_conv_from = NULL;
char_conv_same = 0;
char_conv_latin1ToUtf8 = 0;
char_conv_use_iconv = 0;
}
#endif
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -28,3 +28,4 @@ char * convStrDup(char * string);
void closeCharSetConversion();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -21,19 +21,43 @@
#include "../config.h"
#include "list.h"
#include "myfprintf.h"
#include "log.h"
#include "ack.h"
#include <stdio.h>
#define COMMAND_RETURN_KILL 10
#define COMMAND_RETURN_CLOSE 20
#define COMMAND_RESPOND_ERROR "ACK"
#define COMMAND_RESPOND_OK "OK"
extern char * current_command;
extern int command_listNum;
int proccessListOfCommands(FILE * fp, int * permission, int * expired,
List * list);
int processCommand(FILE * fp, unsigned int * permission, int argArrayLength,
char ** argArray);
int processCommand(FILE * fp, unsigned int * permission, char * commandString);
void initCommands();
void finishCommands();
#define commandSuccess(fp) myfprintf(fp, "OK\n")
#define commandError(fp, error, format, ... ) \
{\
if(current_command) { \
myfprintf(fp, "ACK [%i@%i] {%s} " format "\n", \
(int)error, command_listNum, \
current_command, ##__VA_ARGS__); \
current_command = NULL; \
} \
else { \
myfprintf(fp, "ACK [%i@%i] " format "\n", \
(int)error, command_listNum, \
##__VA_ARGS__); \
} \
}
#endif
......@@ -37,14 +37,14 @@
#define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 27
#define CONF_NUMBER_OF_PARAMS 29
#define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_NUMBER_OF_ALLOW_CATS 1
#define CONF_CONNECTION_TIMEOUT_DEFAULT "60"
#define CONF_MAX_CONNECTIONS_DEFAULT "5"
#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "4096"
#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "16384"
#define CONF_BUFFER_BEFORE_PLAY_DEFAULT "25%"
#define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT "2048"
#define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT "2048"
......@@ -123,7 +123,9 @@ char ** readConf(char * file) {
"filesystem_charset",
"password",
"default_permissions",
"buffer_size"
"buffer_size",
"replaygain",
"audio_output_format"
};
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
......@@ -160,7 +162,7 @@ char ** readConf(char * file) {
if(!(fp=fopen(file,"r"))) {
ERROR("problems opening file %s for reading\n",file);
exit(-1);
exit(EXIT_FAILURE);
}
while(myFgets(string,sizeof(string),fp)) {
......@@ -169,13 +171,13 @@ char ** readConf(char * file) {
if(numberOfArgs==0) continue;
if(2!=numberOfArgs) {
ERROR("improperly formated config line: %s\n",string);
exit(-1);
exit(EXIT_FAILURE);
}
i = 0;
while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++;
if(i>=CONF_NUMBER_OF_PARAMS) {
ERROR("unrecognized line in conf: %s\n",string);
exit(-1);
exit(EXIT_FAILURE);
}
if(conf_params[i]!=NULL) {
if(allowCat[i]) {
......@@ -203,7 +205,7 @@ char ** readConf(char * file) {
if(conf_params[conf_required[i]] == NULL) {
ERROR("%s is unassigned in conf file\n",
conf_strings[conf_required[i]]);
exit(-1);
exit(EXIT_FAILURE);
}
}
......@@ -214,7 +216,7 @@ char ** readConf(char * file) {
{
ERROR("\"%s\" is not an absolute path\n",
conf_params[conf_absolutePaths[i]]);
exit(-1);
exit(EXIT_FAILURE);
}
/* Parse ~ in path */
else if(conf_params[conf_absolutePaths[i]] &&
......@@ -230,7 +232,7 @@ char ** readConf(char * file) {
if((pwd = getpwuid(uid)) == NULL) {
ERROR("problems getting passwd entry "
"for current user\n");
exit(-1);
exit(EXIT_FAILURE);
}
}
else {
......@@ -249,7 +251,7 @@ char ** readConf(char * file) {
ERROR("user \"%s\" not found\n",
&(conf_params[
conf_absolutePaths[i]][1]));
exit(-1);
exit(EXIT_FAILURE);
}
if(foundSlash) *ch = '/';
}
......@@ -268,3 +270,4 @@ char ** readConf(char * file) {
char ** getConf() {
return conf_params;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -48,6 +48,8 @@
#define CONF_PASSWORD 24
#define CONF_DEFAULT_PERMISSIONS 25
#define CONF_BUFFER_SIZE 26
#define CONF_REPLAYGAIN 27
#define CONF_AUDIO_OUTPUT_FORMAT 28
#define CONF_CAT_CHAR "\n"
......@@ -61,3 +63,4 @@ void initConf();
void writeConf(char * file);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -20,39 +20,59 @@
#define DECODE_H
#include "../config.h"
#include "tag.h"
#include "mpd_types.h"
#include "audio.h"
#include <stdio.h>
#include <sys/param.h>
#define DECODE_TYPE_MP3 0
#define DECODE_TYPE_OGG 1
#define DECODE_TYPE_FLAC 2
#define DECODE_TYPE_AUDIOFILE 3
#define DECODE_TYPE_MP4 4
#define DECODE_TYPE_AAC 5
#define DECODE_TYPE_FILE 0
#define DECODE_TYPE_URL 1
#define DECODE_STATE_STOP 0
#define DECODE_STATE_DECODE 1
#define DECODE_STATE_START 1
#define DECODE_STATE_DECODE 2
#define DECODE_ERROR_NOERROR 0
#define DECODE_ERROR_UNKTYPE 1
#define DECODE_ERROR_FILE 2
#define DECODE_ERROR_UNKTYPE 10
#define DECODE_ERROR_FILE 20
#define DECODE_SUFFIX_MP3 1
#define DECODE_SUFFIX_OGG 2
#define DECODE_SUFFIX_FLAC 3
#define DECODE_SUFFIX_AAC 4
#define DECODE_SUFFIX_MP4 5
#define DECODE_SUFFIX_WAVE 6
#define DECODE_METADATA_LENGTH 4096
typedef struct _DecoderControl {
mpd_sint8 state;
mpd_sint8 stop;
mpd_sint8 start;
mpd_uint16 error;
mpd_sint8 seek;
mpd_sint8 seekError;
double seekWhere;
char file[MAXPATHLEN+1];
volatile mpd_sint8 state;
volatile mpd_sint8 stop;
volatile mpd_sint8 start;
volatile mpd_uint16 error;
volatile mpd_sint8 seek;
volatile mpd_sint8 seekError;
volatile mpd_sint8 seekable;
volatile mpd_sint8 cycleLogFiles;
volatile double seekWhere;
AudioFormat audioFormat;
char utf8url[MAXPATHLEN+1];
volatile float totalTime;
volatile mpd_sint8 metadataSet;
char metadata[DECODE_METADATA_LENGTH];
volatile mpd_sint16 title;
volatile mpd_sint16 artist;
volatile mpd_sint16 album;
} DecoderControl;
void decodeSigHandler(int sig);
void decode();
void copyMpdTagToDecoderControlMetadata(DecoderControl * dc, MpdTag * tag);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -22,11 +22,22 @@
#include "../config.h"
#include "song.h"
#include "list.h"
#include <stdio.h>
#include <sys/param.h>
extern char directorydb[MAXPATHLEN+1];
extern char * directory_db;
void readDirectoryDBIfUpdateIsFinished();
void clearUpdatePid();
int isUpdatingDB();
void directory_sigChldHandler(int pid, int status);
int updateInit(FILE * fp, List * pathList);
void initMp3Directory();
......@@ -38,7 +49,7 @@ int writeDirectoryDB();
int readDirectoryDB();
int updateMp3Directory(FILE * fp);
void updateMp3Directory();
int printAllIn(FILE * fp, char * name);
......@@ -54,8 +65,9 @@ int countSongsIn(FILE * fp, char * name);
unsigned long sumSongTimesIn(FILE * fp, char * name);
Song * getSong(char * file);
Song * getSongFromDB(char * file);
time_t getDbModTime();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "flac_decode.h"
#ifdef HAVE_FLAC
#include "utils.h"
#include "log.h"
#include "pcm_utils.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <FLAC/file_decoder.h>
#include <FLAC/metadata.h>
typedef struct {
unsigned char chunk[CHUNK_SIZE];
int chunk_length;
float time;
int bitRate;
FLAC__uint64 position;
Buffer * cb;
AudioFormat * af;
DecoderControl * dc;
char * file;
} FlacData;
/* this code is based on flac123, from flac-tools */
int flacSendChunk(FlacData * data);
void flacPlayfile(const char * file, Buffer * cb, ao_sample_format * format);
void flacError(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *);
void flacPrintErroredState(FLAC__FileDecoderState state, char * file);
void flacMetadata(const FLAC__FileDecoder *, const FLAC__StreamMetadata *, void *);
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *, const FLAC__Frame *, const FLAC__int32 * const buf[], void *);
void flacPlayFile(char *file, Buffer * cb, AudioFormat * af,
DecoderControl *dc)
{
FLAC__FileDecoder * flacDec;
FlacData data;
int status = 1;
data.chunk_length = 0;
data.time = 0;
data.position = 0;
data.bitRate = 0;
data.cb = cb;
data.af = af;
data.dc = dc;
data.file = file;
if(!(flacDec = FLAC__file_decoder_new())) return;
/*status&=FLAC__file_decoder_set_md5_checking(flacDec,1);*/
status&=FLAC__file_decoder_set_filename(flacDec,file);
status&=FLAC__file_decoder_set_write_callback(flacDec,flacWrite);
status&=FLAC__file_decoder_set_metadata_callback(flacDec,flacMetadata);
status&=FLAC__file_decoder_set_error_callback(flacDec,flacError);
status&=FLAC__file_decoder_set_client_data(flacDec, (void *)&data);
if(!status) {
ERROR("flac problem before init(): %s\n",file);
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
FLAC__file_decoder_delete(flacDec);
return;
}
if(FLAC__file_decoder_init(flacDec)!=
FLAC__STREAM_DECODER_SEARCH_FOR_METADATA)
{
ERROR("flac problem doing init(): %s\n",file);
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
FLAC__file_decoder_delete(flacDec);
return;
}
if(!FLAC__file_decoder_process_until_end_of_metadata(flacDec)) {
ERROR("flac problem reading metadata: %s\n",file);
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),file);
FLAC__file_decoder_delete(flacDec);
return;
}
while(1) {
FLAC__file_decoder_process_single(flacDec);
if(FLAC__file_decoder_get_state(flacDec)!=
FLAC__FILE_DECODER_OK)
{
break;
}
if(dc->seek) {
FLAC__uint64 sampleToSeek = dc->seekWhere*
af->sampleRate+0.5;
cb->end = cb->begin;
cb->wrap = 0;
if(FLAC__file_decoder_seek_absolute(flacDec,
sampleToSeek))
{
data.time = ((float)sampleToSeek)/
af->sampleRate;
data.position = 0;
}
dc->seek = 0;
}
}
/* I don't think we need this bit here! =shank */
/*FLAC__file_decoder_process_until_end_of_file(flacDec);*/
if(!dc->stop) {
flacPrintErroredState(FLAC__file_decoder_get_state(flacDec),
file);
FLAC__file_decoder_finish(flacDec);
}
FLAC__file_decoder_delete(flacDec);
/* send last little bit */
if(data.chunk_length>0 && !dc->stop) flacSendChunk(&data);
}
void flacError(const FLAC__FileDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *fdata) {
FlacData * data = (FlacData *) fdata;
if(data->dc->stop) return;
switch(status) {
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
ERROR("flac lost sync: %s\n",data->file);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
ERROR("bad header %s\n",data->file);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
ERROR("crc mismatch %s\n",data->file);
break;
default:
ERROR("unknow flac error %s\n",data->file);
}
}
void flacPrintErroredState(FLAC__FileDecoderState state, char * file) {
switch(state) {
case FLAC__FILE_DECODER_ERROR_OPENING_FILE:
ERROR("error opening flac: %s\n",file);
break;
case FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR:
ERROR("flac allocation error\n");
break;
case FLAC__FILE_DECODER_SEEK_ERROR:
ERROR("flac seek error: %s\n",file);
break;
case FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR:
ERROR("flac seekable stream error: %s\n",file);
break;
case FLAC__FILE_DECODER_ALREADY_INITIALIZED:
ERROR("flac decoder already initilaized: %s\n",file);
break;
case FLAC__FILE_DECODER_INVALID_CALLBACK:
ERROR("invalid flac callback\n");
break;
case FLAC__FILE_DECODER_UNINITIALIZED:
ERROR("flac decoder uninitialized: %s\n",file);
break;
case FLAC__FILE_DECODER_OK:
case FLAC__FILE_DECODER_END_OF_FILE:
break;
}
}
void flacMetadata(const FLAC__FileDecoder *dec, const FLAC__StreamMetadata *meta, void *data) {
}
int flacSendChunk(FlacData * data) {
while(data->cb->begin==data->cb->end && data->cb->wrap &&
!data->dc->stop && !data->dc->seek)
{
my_usleep(10000);
}
if(data->dc->stop) return -1;
if(data->dc->seek) return 0;
memcpy(data->cb->chunks+data->cb->end*CHUNK_SIZE,data->chunk,
CHUNK_SIZE);
data->cb->chunkSize[data->cb->end] = data->chunk_length;
data->cb->times[data->cb->end] = data->time;
data->cb->bitRate[data->cb->end] = data->bitRate;
data->cb->end++;
if(data->cb->end>=buffered_chunks) {
data->cb->end = 0;
data->cb->wrap = 1;
}
return 0;
}
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *dec, const FLAC__Frame *frame, const FLAC__int32 * const buf[], void * vdata) {
FlacData * data = (FlacData *)vdata;
FLAC__uint32 samples = frame->header.blocksize;
FLAC__uint16 u16;
unsigned char * uc;
int c_samp, c_chan, d_samp;
int i;
float timeChange;
FLAC__uint64 newPosition = 0;
timeChange = ((float)samples)/frame->header.sample_rate;
data->time+= timeChange;
FLAC__file_decoder_get_decode_position(dec,&newPosition);
if(data->position) {
data->bitRate = ((newPosition-data->position)*8.0/timeChange)
/1024+0.5;
}
data->position = newPosition;
for(c_samp = d_samp = 0; c_samp < frame->header.blocksize; c_samp++) {
for(c_chan = 0; c_chan < frame->header.channels;
c_chan++, d_samp++) {
u16 = buf[c_chan][c_samp];
uc = (unsigned char *)&u16;
for(i=0;i<(data->af->bits/8);i++) {
if(data->chunk_length>=CHUNK_SIZE) {
if(flacSendChunk(data)<0) {
return FLAC__STREAM_DECODER_WRITE_STATUS_ABORT;
}
data->chunk_length = 0;
if(data->dc->seek) {
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
}
data->chunk[data->chunk_length++] = *(uc++);
}
}
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
int flac_getAudioFormatAndTime(char * file, AudioFormat * format, float * time) {
FLAC__Metadata_SimpleIterator * it;
FLAC__StreamMetadata * block = NULL;
int found = 0;
int ret = -1;
if(!(it = FLAC__metadata_simple_iterator_new())) return -1;
if(!FLAC__metadata_simple_iterator_init(it,file,1,0)) {
FLAC__metadata_simple_iterator_delete(it);
return -1;
}
do {
if(block) FLAC__metadata_object_delete(block);
block = FLAC__metadata_simple_iterator_get_block(it);
if(block->type == FLAC__METADATA_TYPE_STREAMINFO) found=1;
} while(!found && FLAC__metadata_simple_iterator_next(it));
if(found) {
format->bits = block->data.stream_info.bits_per_sample;
format->bits = 16;
format->sampleRate = block->data.stream_info.sample_rate;
format->channels = block->data.stream_info.channels;
*time = ((float)block->data.stream_info.total_samples)/
format->sampleRate;
ret = 0;
}
if(block) FLAC__metadata_object_delete(block);
FLAC__metadata_simple_iterator_delete(it);
return ret;
}
int getFlacTotalTime(char * file) {
float totalTime;
AudioFormat af;
if(flac_getAudioFormatAndTime(file,&af,&totalTime)<0) return -1;
return (int)(totalTime+0.5);
}
int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(flac_getAudioFormatAndTime(dc->file,af,&(cb->totalTime))<0) {
ERROR("\"%s\" doesn't seem to be a flac\n",dc->file);
return -1;
}
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
flacPlayFile(dc->file,cb,af,dc);
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
#endif
#include "inputPlugin.h"
#include "list.h"
#include "myfprintf.h"
#include <stdlib.h>
#include <string.h>
static List * inputPlugin_list = NULL;
void loadInputPlugin(InputPlugin * inputPlugin) {
if(!inputPlugin) return;
if(!inputPlugin->name) return;
if(inputPlugin->initFunc && inputPlugin->initFunc() < 0) return;
insertInList(inputPlugin_list, inputPlugin->name, (void *)inputPlugin);
}
void unloadInputPlugin(InputPlugin * inputPlugin) {
if(inputPlugin->finishFunc) inputPlugin->finishFunc();
deleteFromList(inputPlugin_list, inputPlugin->name);
}
static int stringFoundInStringArray(char ** array, char * suffix) {
while(array && *array) {
if(strcasecmp(*array, suffix) == 0) return 1;
array++;
}
return 0;
}
InputPlugin * getInputPluginFromSuffix(char * suffix) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin = NULL;
if(suffix == NULL) return NULL;
while(node != NULL) {
plugin = node->data;
if(stringFoundInStringArray(plugin->suffixes, suffix)) {
return plugin;
}
node = node->nextNode;
}
return NULL;
}
InputPlugin * getInputPluginFromMimeType(char * mimeType) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin = NULL;
if(mimeType == NULL) return NULL;
while(node != NULL) {
plugin = node->data;
if(stringFoundInStringArray(plugin->mimeTypes, mimeType)) {
return plugin;
}
node = node->nextNode;
}
return NULL;
}
InputPlugin * getInputPluginFromName(char * name) {
void * plugin = NULL;
findInList(inputPlugin_list, name, &plugin);
return (InputPlugin *)plugin;
}
void printAllInputPluginSuffixes(FILE * fp) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin;
char ** suffixes;
while(node) {
plugin = (InputPlugin *)node->data;
suffixes = plugin->suffixes;
while(suffixes && *suffixes) {
myfprintf(fp, "%s ", *suffixes);
suffixes++;
}
node = node->nextNode;
}
myfprintf(fp, "\n");
}
extern InputPlugin mp3Plugin;
extern InputPlugin oggPlugin;
extern InputPlugin flacPlugin;
extern InputPlugin audiofilePlugin;
extern InputPlugin mp4Plugin;
extern InputPlugin aacPlugin;
extern InputPlugin modPlugin;
void initInputPlugins() {
inputPlugin_list = makeList(NULL);
/* load plugins here */
loadInputPlugin(&mp3Plugin);
loadInputPlugin(&oggPlugin);
loadInputPlugin(&flacPlugin);
loadInputPlugin(&audiofilePlugin);
loadInputPlugin(&mp4Plugin);
loadInputPlugin(&modPlugin);
}
void finishInputPlugins() {
freeList(inputPlugin_list);
}
#ifndef INPUT_PLUGIN_H
#define INPUT_PLUGIN_H
#include "../config.h"
#include "inputStream.h"
#include "decode.h"
#include "outputBuffer.h"
#include "tag.h"
#define INPUT_PLUGIN_STREAM_FILE 0x01
#define INPUT_PLUGIN_STREAM_URL 0x02
typedef int (* InputPlugin_initFunc) ();
typedef void (* InputPlugin_finishFunc) ();
typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
InputStream *);
typedef int (* InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
char * path);
/* file should be the full path! */
typedef MpdTag * (* InputPlugin_tagDupFunc) (char * file);
typedef struct _InputPlugin {
char * name;
InputPlugin_initFunc initFunc;
InputPlugin_finishFunc finishFunc;
InputPlugin_streamDecodeFunc streamDecodeFunc;
InputPlugin_fileDecodeFunc fileDecodeFunc;
InputPlugin_tagDupFunc tagDupFunc;
unsigned char streamTypes;
char ** suffixes;
char ** mimeTypes;
} InputPlugin;
/* individual functions to load/unload plugins */
void loadInputPlugin(InputPlugin * inputPlugin);
void unloadInputPlugin(InputPlugin * inputPlugin);
/* interface for using plugins */
InputPlugin * getInputPluginFromSuffix(char * suffix);
InputPlugin * getInputPluginFromMimeType(char * mimeType);
InputPlugin * getInputPluginFromName(char * name);
void printAllInputPluginSuffixes(FILE * fp);
/* this is where we "load" all the "plugins" ;-) */
void initInputPlugins();
/* this is where we "unload" all the "plugins" */
void finishInputPlugins();
#endif
......@@ -16,16 +16,17 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "aac_decode.h"
#include "../inputPlugin.h"
#ifdef HAVE_FAAD
#define AAC_MAX_CHANNELS 6
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include "../utils.h"
#include "../audio.h"
#include "../log.h"
#include "../inputStream.h"
#include "../outputBuffer.h"
#include <stdio.h>
#include <unistd.h>
......@@ -35,12 +36,12 @@
/* all code here is either based on or copied from FAAD2's frontend code */
typedef struct {
InputStream * inStream;
long bytesIntoBuffer;
long bytesConsumed;
long fileOffset;
unsigned char *buffer;
int atEof;
FILE *infile;
} AacBuffer;
void fillAacBuffer(AacBuffer *b) {
......@@ -53,8 +54,9 @@ void fillAacBuffer(AacBuffer *b) {
}
if(!b->atEof) {
bread = fread((void *)(b->buffer+b->bytesIntoBuffer),1,
b->bytesConsumed,b->infile);
bread = readFromInputStream(b->inStream,
(void *)(b->buffer+b->bytesIntoBuffer),
1,b->bytesConsumed);
if(bread!=b->bytesConsumed) b->atEof = 1;
b->bytesIntoBuffer+=bread;
}
......@@ -132,7 +134,7 @@ int adtsParse(AacBuffer * b, float * length) {
return 1;
}
void initAacBuffer(FILE * fp, AacBuffer * b, float * length,
void initAacBuffer(InputStream * inStream, AacBuffer * b, float * length,
size_t * retFileread, size_t * retTagsize)
{
size_t fileread;
......@@ -143,17 +145,15 @@ void initAacBuffer(FILE * fp, AacBuffer * b, float * length,
memset(b,0,sizeof(AacBuffer));
b->infile = fp;
b->inStream = inStream;
fseek(b->infile,0,SEEK_END);
fileread = ftell(b->infile);
fseek(b->infile,0,SEEK_SET);
fileread = inStream->size;
b->buffer = malloc(FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
memset(b->buffer,0,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
bread = fread(b->buffer,1,FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
b->infile);
bread = readFromInputStream(inStream,b->buffer,1,
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
b->bytesIntoBuffer = bread;
b->bytesConsumed = 0;
b->fileOffset = 0;
......@@ -177,11 +177,10 @@ void initAacBuffer(FILE * fp, AacBuffer * b, float * length,
if((b->buffer[0] == 0xFF) && ((b->buffer[1] & 0xF6) == 0xF0)) {
adtsParse(b, length);
fseek(b->infile, tagsize, SEEK_SET);
seekInputStream(b->inStream, tagsize, SEEK_SET);
bread = fread(b->buffer, 1,
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS,
b->infile);
bread = readFromInputStream(b->inStream, b->buffer, 1,
FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS);
if(bread != FAAD_MIN_STREAMSIZE*AAC_MAX_CHANNELS) b->atEof = 1;
else b->atEof = 0;
b->bytesIntoBuffer = bread;
......@@ -209,12 +208,12 @@ float getAacFloatTotalTime(char * file) {
faacDecConfigurationPtr config;
unsigned long sampleRate;
unsigned char channels;
FILE * fp = fopen(file,"r");
InputStream inStream;
size_t bread;
if(fp==NULL) return -1;
if(openInputStream(&inStream,file) < 0) return -1;
initAacBuffer(fp,&b,&length,&fileread,&tagsize);
initAacBuffer(&inStream,&b,&length,&fileread,&tagsize);
if(length < 0) {
decoder = faacDecOpen();
......@@ -236,7 +235,7 @@ float getAacFloatTotalTime(char * file) {
}
if(b.buffer) free(b.buffer);
fclose(b.infile);
closeInputStream(&inStream);
return length;
}
......@@ -251,7 +250,7 @@ int getAacTotalTime(char * file) {
}
int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
int aac_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
float time;
float totalTime;
faacDecHandle decoder;
......@@ -264,21 +263,18 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
unsigned int sampleCount;
char * sampleBuffer;
size_t sampleBufferLen;
int chunkLen = 0;
/*float * seekTable;
long seekTableEnd = -1;
int seekPositionFound = 0;*/
mpd_uint16 bitRate = 0;
AacBuffer b;
FILE * fp;
InputStream inStream;
if((totalTime = getAacFloatTotalTime(dc->file)) < 0) return -1;
if((totalTime = getAacFloatTotalTime(path)) < 0) return -1;
fp = fopen(dc->file,"r");
if(openInputStream(&inStream, path) < 0) return -1;
if(fp==NULL) return -1;
initAacBuffer(fp,&b,NULL,NULL,NULL);
initAacBuffer(&inStream,&b,NULL,NULL,NULL);
decoder = faacDecOpen();
......@@ -303,14 +299,14 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(bread < 0) {
ERROR("Error not a AAC stream.\n");
faacDecClose(decoder);
fclose(b.infile);
closeInputStream(b.inStream);
if(b.buffer) free(b.buffer);
return -1;
}
af->bits = 16;
dc->audioFormat.bits = 16;
cb->totalTime = totalTime;
dc->totalTime = totalTime;
time = 0.0;
......@@ -332,7 +328,7 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
#endif
if(frameInfo.error > 0) {
ERROR("error decoding AAC file: %s\n",dc->file);
ERROR("error decoding AAC file: %s\n", path);
ERROR("faad2 error: %s\n",
faacDecGetErrorMessage(frameInfo.error));
eof = 1;
......@@ -343,11 +339,12 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
sampleRate = frameInfo.samplerate;
#endif
if(dc->start) {
af->channels = frameInfo.channels;
af->sampleRate = sampleRate;
if(dc->state != DECODE_STATE_DECODE) {
dc->audioFormat.channels = frameInfo.channels;
dc->audioFormat.sampleRate = sampleRate;
getOutputAudioFormat(&(dc->audioFormat),
&(cb->audioFormat));
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
}
advanceAacBuffer(&b,frameInfo.bytesconsumed);
......@@ -357,70 +354,37 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(sampleCount>0) {
bitRate = frameInfo.bytesconsumed*8.0*
frameInfo.channels*sampleRate/
frameInfo.samples/1024+0.5;
frameInfo.samples/1000+0.5;
time+= (float)(frameInfo.samples)/frameInfo.channels/
sampleRate;
}
sampleBufferLen = sampleCount*2;
while(sampleBufferLen>0) {
size_t size = sampleBufferLen>CHUNK_SIZE-chunkLen ?
CHUNK_SIZE-chunkLen:
sampleBufferLen;
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
my_usleep(10000);
}
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}
else if(dc->stop) {
eof = 1;
break;
}
else {
sampleBufferLen-=size;
memcpy(cb->chunks+cb->end*CHUNK_SIZE+chunkLen,
sampleBuffer,size);
cb->times[cb->end] = time;
cb->bitRate[cb->end] = bitRate;
sampleBuffer+=size;
chunkLen+=size;
if(chunkLen>=CHUNK_SIZE) {
cb->chunkSize[cb->end] = CHUNK_SIZE;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
}
sendDataToOutputBuffer(cb, NULL, dc, 0, sampleBuffer,
sampleBufferLen, time, bitRate);
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}
else if(dc->stop) {
eof = 1;
break;
}
} while (!eof);
flushOutputBuffer(cb);
faacDecClose(decoder);
fclose(b.infile);
closeInputStream(b.inStream);
if(b.buffer) free(b.buffer);
if(dc->start) return -1;
if(!dc->stop && !dc->seek && chunkLen>0) {
cb->chunkSize[cb->end] = chunkLen;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
if(dc->state != DECODE_STATE_DECODE) return -1;
if(dc->seek) dc->seek = 0;
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
......@@ -431,4 +395,48 @@ int aac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
return 0;
}
MpdTag * aacTagDup(char * file) {
MpdTag * ret = NULL;
int time;
time = getAacTotalTime(file);
if(time>=0) {
if((ret = id3Dup(file))==NULL) ret = newMpdTag();
ret->time = time;
}
return ret;
}
char * aacSuffixes[] = {"aac", NULL};
InputPlugin aacPlugin =
{
"aac",
NULL,
NULL,
NULL,
aac_decode,
aacTagDup,
INPUT_PLUGIN_STREAM_FILE,
aacSuffixes,
NULL
};
#else
InputPlugin aacPlugin =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
#endif /* HAVE_FAAD */
......@@ -18,15 +18,15 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "audiofile_decode.h"
#include "../inputPlugin.h"
#ifdef HAVE_AUDIOFILE
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include "pcm_utils.h"
#include "../utils.h"
#include "../audio.h"
#include "../log.h"
#include "../pcm_utils.h"
#include "../playerData.h"
#include <stdio.h>
#include <unistd.h>
......@@ -51,39 +51,39 @@ int getAudiofileTotalTime(char * file)
return time;
}
int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
{
int audiofile_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
int fs, frame_count;
AFfilehandle af_fp;
int bits;
mpd_uint16 bitRate;
struct stat st;
if(stat(dc->file,&st) < 0) {
ERROR("failed to stat: %s\n",dc->file);
if(stat(path, &st) < 0) {
ERROR("failed to stat: %s\n", path);
return -1;
}
af_fp = afOpenFile(dc->file,"r", NULL);
af_fp = afOpenFile(path, "r", NULL);
if(af_fp == AF_NULL_FILEHANDLE) {
ERROR("failed to open: %s\n",dc->file);
ERROR("failed to open: %s\n", path);
return -1;
}
afGetSampleFormat(af_fp, AF_DEFAULT_TRACK, &fs, &bits);
af->bits = bits;
af->sampleRate = afGetRate(af_fp, AF_DEFAULT_TRACK);
af->channels = afGetChannels(af_fp,AF_DEFAULT_TRACK);
dc->audioFormat.bits = bits;
dc->audioFormat.sampleRate = afGetRate(af_fp, AF_DEFAULT_TRACK);
dc->audioFormat.channels = afGetChannels(af_fp,AF_DEFAULT_TRACK);
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
frame_count = afGetFrameCount(af_fp,AF_DEFAULT_TRACK);
cb->totalTime = ((float)frame_count/(float)af->sampleRate);
dc->totalTime = ((float)frame_count/(float)dc->audioFormat.sampleRate);
bitRate = st.st_size*8.0/cb->totalTime/1024.0+0.5;
bitRate = st.st_size*8.0/dc->totalTime/1000.0+0.5;
if (af->bits != 8 && af->bits != 16) {
if (dc->audioFormat.bits != 8 && dc->audioFormat.bits != 16) {
ERROR("Only 8 and 16-bit files are supported. %s is %i-bit\n",
dc->file,af->bits);
path, dc->audioFormat.bits);
afCloseFile(af_fp);
return -1;
}
......@@ -91,49 +91,42 @@ int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
fs = (int)afGetFrameSize(af_fp, AF_DEFAULT_TRACK,1);
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
{
int ret, eof = 0, current = 0;
unsigned char chunk[CHUNK_SIZE];
while(!eof) {
if(dc->seek) {
cb->end = cb->begin;
cb->wrap = 0;
current = dc->seekWhere * af->sampleRate;
clearOutputBuffer(cb);
current = dc->seekWhere *
dc->audioFormat.sampleRate;
afSeekFrame(af_fp, AF_DEFAULT_TRACK,current);
dc->seek = 0;
}
ret = afReadFrames(af_fp, AF_DEFAULT_TRACK, chunk, CHUNK_SIZE/fs);
if(ret<=0) eof = 1;
else {
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek){
my_usleep(10000);
}
if(dc->stop) break;
else if(dc->seek) continue;
memcpy(cb->chunks+cb->end*CHUNK_SIZE,chunk,
CHUNK_SIZE);
cb->chunkSize[cb->end] = CHUNK_SIZE;
current += ret;
cb->times[cb->end] = (float)current/(float)af->sampleRate;
cb->bitRate[cb->end] = bitRate;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
sendDataToOutputBuffer(cb,
NULL,
dc,
1,
chunk,
ret*fs,
(float)current /
(float)dc->audioFormat.sampleRate,
bitRate);
if(dc->stop) break;
}
}
if(dc->seek) dc->seek = 0;
flushOutputBuffer(cb);
/*if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}*/
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
......@@ -146,4 +139,46 @@ int audiofile_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
return 0;
}
MpdTag * audiofileTagDup(char * file) {
MpdTag * ret = NULL;
int time = getAudiofileTotalTime(file);
if (time>=0) {
if(!ret) ret = newMpdTag();
ret->time = time;
}
return ret;
}
char * audiofileSuffixes[] = {"wav", "au", "aiff", NULL};
InputPlugin audiofilePlugin =
{
"audiofile",
NULL,
NULL,
NULL,
audiofile_decode,
audiofileTagDup,
INPUT_PLUGIN_STREAM_FILE,
audiofileSuffixes,
NULL
};
#else
InputPlugin audiofilePlugin =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_AUDIOFILE */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
*
* 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
*/
#include "../inputPlugin.h"
#ifdef HAVE_MIKMOD
#include "../utils.h"
#include "../audio.h"
#include "../log.h"
#include "../pcm_utils.h"
#include "../playerData.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <mikmod.h>
/* this is largely copied from alsaplayer */
#define MIKMOD_FRAME_SIZE 4096
static BOOL mod_mpd_Init() {
return VC_Init();
}
static void mod_mpd_Exit() {
VC_Exit();
}
static void mod_mpd_Update() {
}
static BOOL mod_mpd_IsThere() {
return 1;
}
MDRIVER drv_mpd =
{
NULL,
"MPD",
"MPD Output Driver v0.1",
0,
255,
"mpd",
NULL,
mod_mpd_IsThere,
VC_SampleLoad,
VC_SampleUnload,
VC_SampleSpace,
VC_SampleLength,
mod_mpd_Init,
mod_mpd_Exit,
NULL,
VC_SetNumVoices,
VC_PlayStart,
VC_PlayStop,
mod_mpd_Update,
NULL,
VC_VoiceSetVolume,
VC_VoiceGetVolume,
VC_VoiceSetFrequency,
VC_VoiceGetFrequency,
VC_VoiceSetPanning,
VC_VoiceGetPanning,
VC_VoicePlay,
VC_VoiceStop,
VC_VoiceStopped,
VC_VoiceGetPosition,
VC_VoiceRealVolume
};
static int mod_mikModInitiated = 0;
static int mod_mikModInitError = 0;
static int mod_initMikMod() {
if(mod_mikModInitiated) return 0;
if(mod_mikModInitError) return -1;
mod_mikModInitiated = 1;
MikMod_RegisterDriver(&drv_mpd);
MikMod_RegisterAllLoaders();
md_reverb = 0;
md_mode = (DMODE_SOFT_MUSIC | DMODE_SOFT_SNDFX | DMODE_STEREO |
DMODE_16BITS);
if(MikMod_Init("")) {
ERROR("Could not init MikMod: %s\n",
MikMod_strerror(MikMod_errno));
mod_mikModInitError = 1;
return -1;
}
return 0;
}
void mod_finishMikMod() {
MikMod_Exit();
}
typedef struct _mod_Data {
MODULE * moduleHandle;
SBYTE * audio_buffer;
} mod_Data;
static mod_Data * mod_open(char * path) {
MODULE * moduleHandle;
mod_Data * data;
if(!(moduleHandle = Player_Load(path, 255, 0))) return NULL;
data = malloc(sizeof(mod_Data));
data->audio_buffer = malloc(MIKMOD_FRAME_SIZE);
data->moduleHandle = moduleHandle;
Player_Start(data->moduleHandle);
return data;
}
static void mod_close(mod_Data * data) {
Player_Stop();
Player_Free(data->moduleHandle);
free(data->audio_buffer);
free(data);
}
int mod_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
mod_Data * data;
float time = 0.0;
int ret;
float secPerByte;
if(mod_initMikMod() < 0) return -1;
if(!(data = mod_open(path))) {
ERROR("failed to open mod: %s\n", path);
return -1;
}
dc->audioFormat.bits = 16;
dc->audioFormat.sampleRate = 44100;
dc->audioFormat.channels = 2;
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
secPerByte = 1.0/((dc->audioFormat.bits*dc->audioFormat.channels/8.0)*
(float)dc->audioFormat.sampleRate);
dc->state = DECODE_STATE_DECODE;
while(1) {
if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}
if(dc->stop) break;
if(!Player_Active()) break;
ret = VC_WriteBytes(data->audio_buffer, MIKMOD_FRAME_SIZE);
time += ret*secPerByte;
sendDataToOutputBuffer(cb, NULL, dc, 0,
(char *)data->audio_buffer, ret, time,
0);
}
flushOutputBuffer(cb);
mod_close(data);
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
MpdTag * modTagDup(char * file) {
MpdTag * ret = NULL;
MODULE * moduleHandle;
if(mod_initMikMod() < 0) return NULL;
if(!(moduleHandle = Player_Load(file, 255, 0))) return NULL;
Player_Free(moduleHandle);
ret = newMpdTag();
ret->time = 0;
ret->title = Player_LoadTitle(file);
return ret;
}
char * modSuffixes[] = {"amf",
"dsm",
"far",
"gdm",
"imf",
"it",
"med",
"mod",
"mtm",
"s3m",
"stm",
"stx",
"ult",
"uni",
"xm",
NULL};
InputPlugin modPlugin =
{
"audiofile",
NULL,
mod_finishMikMod,
NULL,
mod_decode,
modTagDup,
INPUT_PLUGIN_STREAM_FILE,
modSuffixes,
NULL
};
#else
InputPlugin modPlugin =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_AUDIOFILE */
......@@ -16,17 +16,19 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "mp4_decode.h"
#include "../inputPlugin.h"
#ifdef HAVE_FAAD
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include "pcm_utils.h"
#include "../utils.h"
#include "../audio.h"
#include "../log.h"
#include "../pcm_utils.h"
#include "../inputStream.h"
#include "../outputBuffer.h"
#include "../decode.h"
#include "mp4ff/mp4ff.h"
#include "../mp4ff/mp4ff.h"
#include <stdio.h>
#include <unistd.h>
......@@ -72,17 +74,18 @@ int mp4_getAACTrack(mp4ff_t *infile) {
return -1;
}
uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length) {
return fread(buffer, 1, length, (FILE*)user_data);
uint32_t mp4_inputStreamReadCallback(void *inStream, void *buffer,
uint32_t length)
{
return readFromInputStream((InputStream*) inStream, buffer, 1, length);
}
uint32_t mp4_seekCallback(void *user_data, uint64_t position) {
return fseek((FILE*)user_data, position, SEEK_SET);
uint32_t mp4_inputStreamSeekCallback(void *inStream, uint64_t position) {
return seekInputStream((InputStream *) inStream, position, SEEK_SET);
}
int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
FILE * fh;
int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char * path) {
mp4ff_t * mp4fh;
mp4ff_callback_t * mp4cb;
int32_t track;
......@@ -103,29 +106,28 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
char * sampleBuffer;
size_t sampleBufferLen;
unsigned int initial = 1;
int chunkLen = 0;
float * seekTable;
long seekTableEnd = -1;
int seekPositionFound = 0;
long offset;
mpd_uint16 bitRate = 0;
InputStream inStream;
fh = fopen(dc->file,"r");
if(!fh) {
ERROR("failed to open %s\n",dc->file);
if(openInputStream(&inStream, path) < 0) {
ERROR("failed to open %s\n", path);
return -1;
}
mp4cb = malloc(sizeof(mp4ff_callback_t));
mp4cb->read = mp4_readCallback;
mp4cb->seek = mp4_seekCallback;
mp4cb->user_data = fh;
mp4cb->read = mp4_inputStreamReadCallback;
mp4cb->seek = mp4_inputStreamSeekCallback;
mp4cb->user_data = &inStream;
mp4fh = mp4ff_open_read(mp4cb);
if(!mp4fh) {
ERROR("Input does not appear to be a mp4 stream.\n");
free(mp4cb);
fclose(fh);
closeInputStream(&inStream);
return -1;
}
......@@ -133,7 +135,7 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(track < 0) {
ERROR("No AAC track found in mp4 stream.\n");
mp4ff_close(mp4fh);
fclose(fh);
closeInputStream(&inStream);
free(mp4cb);
return -1;
}
......@@ -150,7 +152,7 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
#endif
faacDecSetConfiguration(decoder,config);
af->bits = 16;
dc->audioFormat.bits = 16;
mp4Buffer = NULL;
mp4BufferSize = 0;
......@@ -163,12 +165,12 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
faacDecClose(decoder);
mp4ff_close(mp4fh);
free(mp4cb);
fclose(fh);
closeInputStream(&inStream);
return -1;
}
af->sampleRate = sampleRate;
af->channels = channels;
dc->audioFormat.sampleRate = sampleRate;
dc->audioFormat.channels = channels;
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
scale = mp4ff_time_scale(mp4fh,track);
......@@ -178,11 +180,11 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
ERROR("Error getting audio format of mp4 AAC track.\n");
faacDecClose(decoder);
mp4ff_close(mp4fh);
fclose(fh);
closeInputStream(&inStream);
free(mp4cb);
return -1;
}
cb->totalTime = ((float)time)/scale;
dc->totalTime = ((float)time)/scale;
numSamples = mp4ff_num_samples(mp4fh,track);
......@@ -217,9 +219,7 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(dc->seek && seekPositionFound) {
seekPositionFound = 0;
chunkLen = 0;
cb->end = cb->begin;
cb->wrap = 0;
clearOutputBuffer(cb);
dc->seek = 0;
}
......@@ -241,22 +241,23 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(mp4Buffer) free(mp4Buffer);
if(frameInfo.error > 0) {
ERROR("error decoding MP4 file: %s\n",dc->file);
ERROR("error decoding MP4 file: %s\n", path);
ERROR("faad2 error: %s\n",
faacDecGetErrorMessage(frameInfo.error));
eof = 1;
break;
}
if(dc->start) {
if(dc->state != DECODE_STATE_DECODE) {
channels = frameInfo.channels;
#ifdef HAVE_FAACDECFRAMEINFO_SAMPLERATE
scale = frameInfo.samplerate;
#endif
af->sampleRate = scale;
af->channels = frameInfo.channels;
dc->audioFormat.sampleRate = scale;
dc->audioFormat.channels = frameInfo.channels;
getOutputAudioFormat(&(dc->audioFormat),
&(cb->audioFormat));
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
}
if(channels*(dur+offset) > frameInfo.samples) {
......@@ -270,7 +271,7 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
initial =0;
bitRate = frameInfo.bytesconsumed*8.0*
frameInfo.channels*scale/
frameInfo.samples/1024+0.5;
frameInfo.samples/1000+0.5;
}
......@@ -278,61 +279,28 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
sampleBuffer+=offset*channels*2;
while(sampleBufferLen>0 && !dc->seek) {
size_t size = sampleBufferLen>CHUNK_SIZE-chunkLen ?
CHUNK_SIZE-chunkLen:
sampleBufferLen;
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
my_usleep(10000);
}
if(dc->stop) {
eof = 1;
break;
}
else if(!dc->seek) {
sampleBufferLen-=size;
memcpy(cb->chunks+cb->end*CHUNK_SIZE+chunkLen,
sampleBuffer,size);
cb->times[cb->end] = time;
cb->bitRate[cb->end] = bitRate;
sampleBuffer+=size;
chunkLen+=size;
if(chunkLen>=CHUNK_SIZE) {
cb->chunkSize[cb->end] = CHUNK_SIZE;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
}
sendDataToOutputBuffer(cb, NULL, dc, 1, sampleBuffer,
sampleBufferLen, time, bitRate);
if(dc->stop) {
eof = 1;
break;
}
}
flushOutputBuffer(cb);
free(seekTable);
faacDecClose(decoder);
mp4ff_close(mp4fh);
fclose(fh);
closeInputStream(&inStream);
free(mp4cb);
if(dc->start) return -1;
if(dc->state != DECODE_STATE_DECODE) return -1;
if(!dc->stop && !dc->seek && chunkLen>0) {
cb->chunkSize[cb->end] = chunkLen;
++cb->end;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
chunkLen = 0;
}
if(dc->seek) dc->seek = 0;
/*if(dc->seek) {
dc->seekError = 1;
dc->seek = 0;
}*/
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
......@@ -343,4 +311,120 @@ int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
return 0;
}
MpdTag * mp4DataDup(char * file, int * mp4MetadataFound) {
MpdTag * ret = NULL;
InputStream inStream;
mp4ff_t * mp4fh;
mp4ff_callback_t * cb;
int32_t track;
int32_t time;
int32_t scale;
*mp4MetadataFound = 0;
if(openInputStream(&inStream, file) < 0) return NULL;
cb = malloc(sizeof(mp4ff_callback_t));
cb->read = mp4_inputStreamReadCallback;
cb->seek = mp4_inputStreamSeekCallback;
cb->user_data = &inStream;
mp4fh = mp4ff_open_read(cb);
if(!mp4fh) {
free(cb);
closeInputStream(&inStream);
return NULL;
}
track = mp4_getAACTrack(mp4fh);
if(track < 0) {
mp4ff_close(mp4fh);
closeInputStream(&inStream);
free(cb);
return NULL;
}
ret = newMpdTag();
time = mp4ff_get_track_duration_use_offsets(mp4fh,track);
scale = mp4ff_time_scale(mp4fh,track);
if(scale < 0) {
mp4ff_close(mp4fh);
closeInputStream(&inStream);
free(cb);
freeMpdTag(ret);
return NULL;
}
ret->time = ((float)time)/scale+0.5;
if(!mp4ff_meta_get_artist(mp4fh,&ret->artist)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_album(mp4fh,&ret->album)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_title(mp4fh,&ret->title)) {
*mp4MetadataFound = 1;
}
if(!mp4ff_meta_get_track(mp4fh,&ret->track)) {
*mp4MetadataFound = 1;
}
mp4ff_close(mp4fh);
closeInputStream(&inStream);
free(cb);
return ret;
}
MpdTag * mp4TagDup(char * file) {
MpdTag * ret = NULL;
int mp4MetadataFound = 0;
ret = mp4DataDup(file, &mp4MetadataFound);
if(!ret) return NULL;
if(!mp4MetadataFound) {
MpdTag * temp = id3Dup(file);
if(temp) {
temp->time = ret->time;
freeMpdTag(ret);
ret = temp;
}
}
return ret;
}
char * mp4Suffixes[] = {"m4a", "mp4", NULL};
InputPlugin mp4Plugin =
{
"mp4",
NULL,
NULL,
NULL,
mp4_decode,
mp4TagDup,
INPUT_PLUGIN_STREAM_FILE,
mp4Suffixes,
NULL
};
#else
InputPlugin mp4Plugin =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_FAAD */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "../inputPlugin.h"
#ifdef HAVE_OGG
#include "../utils.h"
#include "../audio.h"
#include "../log.h"
#include "../pcm_utils.h"
#include "../inputStream.h"
#include "../outputBuffer.h"
#include "../replayGain.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/vorbisfile.h>
#include <errno.h>
#ifdef WORDS_BIGENDIAN
#define OGG_DECODE_USE_BIGENDIAN 1
#else
#define OGG_DECODE_USE_BIGENDIAN 0
#endif
typedef struct _OggCallbackData {
InputStream * inStream;
DecoderControl * dc;
} OggCallbackData;
/* this is just for tag parsing for db import! */
int getOggTotalTime(char * file) {
OggVorbis_File vf;
FILE * oggfp;
int totalTime;
if(!(oggfp = fopen(file,"r"))) return -1;
if(ov_open(oggfp, &vf, NULL, 0) < 0) {
fclose(oggfp);
return -1;
}
totalTime = ov_time_total(&vf,-1)+0.5;
ov_clear(&vf);
return totalTime;
}
size_t ogg_read_cb(void * ptr, size_t size, size_t nmemb, void * vdata)
{
size_t ret = 0;
OggCallbackData * data = (OggCallbackData *)vdata;
while(1) {
ret = readFromInputStream(data->inStream,ptr,size,nmemb);
if(ret == 0 && !inputStreamAtEOF(data->inStream) &&
!data->dc->stop)
{
my_usleep(10000);
}
else break;
}
errno = 0;
/*if(ret<0) errno = ((InputStream *)inStream)->error;*/
return ret;
}
int ogg_seek_cb(void * vdata, ogg_int64_t offset, int whence) {
OggCallbackData * data = (OggCallbackData *)vdata;
return seekInputStream(data->inStream,offset,whence);
}
int ogg_close_cb(void * vdata) {
OggCallbackData * data = (OggCallbackData *)vdata;
return closeInputStream(data->inStream);
}
long ogg_tell_cb(void * vdata) {
OggCallbackData * data = (OggCallbackData *)vdata;
return (long)(data->inStream->offset);
}
char * ogg_parseComment(char * comment, char * needle) {
int len = strlen(needle);
if(strncasecmp(comment, needle, len) == 0 && *(comment+len) == '=') {
return comment+len+1;
}
return NULL;
}
float ogg_getReplayGainScale(char ** comments) {
int trackGainFound = 0;
int albumGainFound = 0;
float trackGain = 1.0;
float albumGain = 1.0;
float trackPeak = 0.0;
float albumPeak = 0.0;
char * temp;
int replayGainState = getReplayGainState();
if(replayGainState == REPLAYGAIN_OFF) return 1.0;
while(*comments) {
if((temp = ogg_parseComment(*comments,"replaygain_track_gain")))
{
trackGain = atof(temp);
trackGainFound = 1;
}
else if((temp = ogg_parseComment(*comments,
"replaygain_album_gain")))
{
albumGain = atof(temp);
albumGainFound = 1;
}
else if((temp = ogg_parseComment(*comments,
"replaygain_track_peak")))
{
trackPeak = atof(temp);
}
else if((temp = ogg_parseComment(*comments,
"replaygain_album_peak")))
{
albumPeak = atof(temp);
}
comments++;
}
switch(replayGainState) {
case REPLAYGAIN_ALBUM:
if(albumGainFound) {
return computeReplayGainScale(albumGain,albumPeak);
}
default:
return computeReplayGainScale(trackGain,trackPeak);
}
return 1.0;
}
MpdTag * oggCommentsParse(char ** comments) {
MpdTag * ret = NULL;
char * temp;
while(*comments) {
if((temp = ogg_parseComment(*comments,"artist"))) {
if(!ret) ret = newMpdTag();
if(!ret->artist) {
ret->artist = strdup(temp);
}
}
else if((temp = ogg_parseComment(*comments,"title"))) {
if(!ret) ret = newMpdTag();
if(!ret->title) {
ret->title = strdup(temp);
}
}
else if((temp = ogg_parseComment(*comments,"album"))) {
if(!ret) ret = newMpdTag();
if(!ret->album) {
ret->album = strdup(temp);
}
}
else if((temp = ogg_parseComment(*comments,"tracknumber"))) {
if(!ret) ret = newMpdTag();
if(!ret->track) {
ret->track = strdup(temp);
}
}
comments++;
}
return ret;
}
void putOggCommentsIntoDecoderControlMetadata(DecoderControl * dc,
char ** comments)
{
MpdTag * tag;
if(dc->metadataSet) return;
tag = oggCommentsParse(comments);
if(!tag) return;
copyMpdTagToDecoderControlMetadata(dc, tag);
freeMpdTag(tag);
}
int ogg_decode(OutputBuffer * cb, DecoderControl * dc, InputStream * inStream)
{
OggVorbis_File vf;
ov_callbacks callbacks;
OggCallbackData data;
int current_section;
int eof = 0;
long ret;
#define OGG_CHUNK_SIZE 4096
char chunk[OGG_CHUNK_SIZE];
int chunkpos = 0;
long bitRate = 0;
long test;
float replayGainScale;
char ** comments;
data.inStream = inStream;
data.dc = dc;
callbacks.read_func = ogg_read_cb;
callbacks.seek_func = ogg_seek_cb;
callbacks.close_func = ogg_close_cb;
callbacks.tell_func = ogg_tell_cb;
if(ov_open_callbacks(&data, &vf, NULL, 0, callbacks) < 0) {
closeInputStream(inStream);
if(!dc->stop) {
ERROR("Input does not appear to be an Ogg Vorbis stream.\n");
return -1;
}
else {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
return 0;
}
{
vorbis_info *vi=ov_info(&vf,-1);
dc->audioFormat.bits = 16;
dc->audioFormat.channels = vi->channels;
dc->audioFormat.sampleRate = vi->rate;
getOutputAudioFormat(&(dc->audioFormat),&(cb->audioFormat));
}
dc->totalTime = ov_time_total(&vf,-1);
if(dc->totalTime < 0) dc->totalTime = 0;
comments = ov_comment(&vf, -1)->user_comments;
putOggCommentsIntoDecoderControlMetadata(dc, comments);
dc->state = DECODE_STATE_DECODE;
replayGainScale = ogg_getReplayGainScale(comments);
while(!eof) {
if(dc->seek) {
if(0 == ov_time_seek_page(&vf,dc->seekWhere)) {
clearOutputBuffer(cb);
chunkpos = 0;
}
else dc->seekError = 1;
dc->seek = 0;
}
ret = ov_read(&vf, chunk+chunkpos,
OGG_CHUNK_SIZE-chunkpos,
OGG_DECODE_USE_BIGENDIAN,
2, 1, &current_section);
if(ret <= 0 && ret != OV_HOLE) {
eof = 1;
break;
}
if(ret == OV_HOLE) ret = 0;
chunkpos+=ret;
if(chunkpos >= OGG_CHUNK_SIZE) {
if((test = ov_bitrate_instant(&vf))>0) {
bitRate = test/1000;
}
doReplayGain(chunk,ret,&(dc->audioFormat),
replayGainScale);
sendDataToOutputBuffer(cb, inStream, dc,
inStream->seekable,
chunk, chunkpos,
ov_time_tell(&vf),
bitRate);
if(dc->stop) break;
chunkpos = 0;
}
}
if(!dc->stop && chunkpos > 0) {
sendDataToOutputBuffer(cb, NULL, dc, inStream->seekable,
chunk, chunkpos,
ov_time_tell(&vf), bitRate);
}
ov_clear(&vf);
flushOutputBuffer(cb);
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
MpdTag * oggTagDup(char * file) {
MpdTag * ret = NULL;
FILE * fp;
OggVorbis_File vf;
fp = fopen(file,"r");
if(!fp) return NULL;
if(ov_open(fp,&vf,NULL,0)<0) {
fclose(fp);
return NULL;
}
ret = oggCommentsParse(ov_comment(&vf,-1)->user_comments);
if(!ret) ret = newMpdTag();
ret->time = (int)(ov_time_total(&vf,-1)+0.5);
ov_clear(&vf);
return ret;
}
char * oggSuffixes[] = {"ogg", NULL};
char * oggMimeTypes[] = {"application/ogg", NULL};
InputPlugin oggPlugin =
{
"ogg",
NULL,
NULL,
ogg_decode,
NULL,
oggTagDup,
INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
oggSuffixes,
oggMimeTypes
};
#else
InputPlugin oggPlugin =
{
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "inputStream.h"
#include "inputStream_file.h"
#include "inputStream_http.h"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int openInputStream(InputStream * inStream, char * url) {
if(inputStream_fileOpen(inStream,url) == 0) return 0;
if(inputStream_httpOpen(inStream,url) == 0) return 0;
return -1;
}
int seekInputStream(InputStream * inStream, long offset, int whence) {
return inStream->seekFunc(inStream,offset,whence);
}
size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
size_t nmemb)
{
return inStream->readFunc(inStream,ptr,size,nmemb);
}
int closeInputStream(InputStream * inStream) {
return inStream->closeFunc(inStream);
}
int inputStreamAtEOF(InputStream * inStream) {
return inStream->atEOFFunc(inStream);
}
int bufferInputStream(InputStream * inStream) {
return inStream->bufferFunc(inStream);
}
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#ifndef INPUT_STREAM_H
#define INPUT_STREAM_H
#include <stdlib.h>
typedef struct _InputStream InputStream;
typedef int (* InputStreamSeekFunc) (InputStream * inStream, long offset,
int whence);
typedef size_t (* InputStreamReadFunc) (InputStream * inStream, void * ptr, size_t size,
size_t nmemb);
typedef int (* InputStreamCloseFunc) (InputStream * inStream);
typedef int (* InputStreamAtEOFFunc) (InputStream * inStream);
typedef int (* InputStreamBufferFunc) (InputStream * inStream);
struct _InputStream {
int error;
long offset;
size_t size;
char * mime;
int seekable;
/* don't touc this stuff */
InputStreamSeekFunc seekFunc;
InputStreamReadFunc readFunc;
InputStreamCloseFunc closeFunc;
InputStreamAtEOFFunc atEOFFunc;
InputStreamBufferFunc bufferFunc;
void * data;
char * metaTitle;
};
int isUrlSaneForInputStream(char * url);
/* if an error occurs for these 3 functions, then -1 is returned and errno
for the input stream is set */
int openInputStream(InputStream * inStream, char * url);
int seekInputStream(InputStream * inStream, long offset, int whence);
int closeInputStream(InputStream * inStream);
int inputStreamAtEOF(InputStream * inStream);
/* return value: -1 is error, 1 inidicates stuff was buffered, 0 means nothing
was buffered */
int bufferInputStream(InputStream * inStream);
size_t readFromInputStream(InputStream * inStream, void * ptr, size_t size,
size_t nmemb);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "inputStream_file.h"
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
int inputStream_fileOpen(InputStream * inStream, char * filename) {
FILE * fp;
fp = fopen(filename,"r");
if(!fp) {
inStream->error = errno;
return -1;
}
inStream->offset = 0;
inStream->seekable = 1;
inStream->mime = NULL;
inStream->metaTitle = NULL;
fseek(fp,0,SEEK_END);
inStream->size = ftell(fp);
fseek(fp,0,SEEK_SET);
inStream->data = fp;
inStream->seekFunc = inputStream_fileSeek;
inStream->closeFunc = inputStream_fileClose;
inStream->readFunc = inputStream_fileRead;
inStream->atEOFFunc = inputStream_fileAtEOF;
inStream->bufferFunc = inputStream_fileBuffer;
return 0;
}
int inputStream_fileSeek(InputStream * inStream, long offset, int whence) {
if(fseek((FILE *)inStream->data,offset,whence)==0) {
inStream->offset = ftell((FILE *)inStream->data);
}
else {
inStream->error = errno;
return -1;
}
return 0;
}
size_t inputStream_fileRead(InputStream * inStream, void * ptr, size_t size,
size_t nmemb)
{
size_t readSize;
readSize = fread(ptr,size,nmemb,(FILE *)inStream->data);
inStream->offset = ftell((FILE *)inStream->data);
return readSize;
}
int inputStream_fileClose(InputStream * inStream) {
if(fclose((FILE *)inStream->data)<0) {
inStream->error = errno;
}
else return -1;
return 0;
}
int inputStream_fileAtEOF(InputStream * inStream) {
return feof((FILE *)inStream->data);
}
int inputStream_fileBuffer(InputStream * inStream) {
return 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -16,20 +16,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef MP3_DECODE_H
#define MP3_DECODE_H
#ifndef INPUT_STREAM_FILE_H
#define INPUT_STREAM_FILE_H
#include "../config.h"
#include "inputStream.h"
#ifdef HAVE_MAD
int inputStream_fileOpen(InputStream * inStream, char * filename);
#include "playerData.h"
int inputStream_fileSeek(InputStream * inStream, long offset, int whence);
/* this is primarily used in tag.c */
int getMp3TotalTime(char * file);
size_t inputStream_fileRead(InputStream * inStream, void * ptr, size_t size,
size_t nmemb);
int mp3_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
int inputStream_fileClose(InputStream * inStream);
#endif
int inputStream_fileAtEOF(InputStream * inStream);
int inputStream_fileBuffer(InputStream * inStream);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -16,17 +16,23 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef OGG_DECODE_H
#define OGG_DECODE_H
#ifndef INPUT_STREAM_HTTP_H
#define INPUT_STREAM_HTTP_H
#include "../config.h"
#include "inputStream.h"
#include "playerData.h"
int inputStream_httpOpen(InputStream * inStream, char * filename);
#include <stdio.h>
int inputStream_httpSeek(InputStream * inStream, long offset, int whence);
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
size_t inputStream_httpRead(InputStream * inStream, void * ptr, size_t size,
size_t nmemb);
int getOggTotalTime(char * file);
int inputStream_httpClose(InputStream * inStream);
int inputStream_httpAtEOF(InputStream * inStream);
int inputStream_httpBuffer(InputStream * inStream);
#endif
/* vim:set shiftwidth=8 tabstop=8 expandtab: */
......@@ -17,7 +17,6 @@
*/
#include "interface.h"
#include "buffer2array.h"
#include "command.h"
#include "conf.h"
#include "list.h"
......@@ -42,7 +41,7 @@
#include <errno.h>
#include <signal.h>
#define GREETING "MPD"
#define GREETING "OK MPD"
#define INTERFACE_MAX_BUFFER_LENGTH MAXPATHLEN+1024
#define INTERFACE_LIST_MODE_BEGIN "command_list_begin"
......@@ -85,14 +84,13 @@ void openInterface(Interface * interface, int fd) {
assert(interface->open==0);
blockSignals();
interface->bufferLength = 0;
interface->fd = fd;
/* fcntl(interface->fd,F_SETOWN,(int)getpid()); */
flags = fcntl(fd,F_GETFL);
while((flags = fcntl(fd,F_GETFL))<0 && errno==EINTR);
flags|=O_NONBLOCK;
fcntl(interface->fd,F_SETFL,flags);
interface->fp = fdopen(fd,"rw");
while(fcntl(interface->fd,F_SETFL,flags)<0 && errno==EINTR);
while((interface->fp = fdopen(fd,"rw"))==NULL && errno==EINTR);
interface->open = 1;
interface->lastTime = time(NULL);
interface->commandList = NULL;
......@@ -122,10 +120,7 @@ void openInterface(Interface * interface, int fd) {
#endif
interface->outBuffer = malloc(interface->outBufSize);
unblockSignals();
myfprintf(interface->fp,"%s %s %s\n",COMMAND_RESPOND_OK,GREETING,
VERSION);
myfprintf(interface->fp, "%s %s\n", GREETING, VERSION);
printInterfaceOutBuffer(interface);
}
......@@ -222,35 +217,26 @@ int interfaceReadInput(Interface * interface) {
closeInterface(interface);
}
else if(interface->buffer[interface->bufferLength-1]=='\n') {
char ** argArray;
int argArrayLength;
interface->buffer[interface->bufferLength-1] = '\0';
interface->bufferLength = 0;
argArrayLength = buffer2array(interface->buffer,&argArray);
if(interface->commandList) {
if(argArrayLength==0);
else if(strcmp(argArray[0],INTERFACE_LIST_MODE_END)==0) {
ListNode * node = interface->commandList->firstNode;
ret = 0;
while(node!=NULL) {
char ** argArray;
int argArrayLength;
argArrayLength = buffer2array((char *)node->data,&argArray);
DEBUG("interface %i: process command \"%s\"\n",interface->num,node->data);
ret = processCommand(interface->fp,&(interface->permission),argArrayLength,argArray);
DEBUG("interface %i: command returned %i\n",interface->num,ret);
freeArgArray(argArray,argArrayLength);
node = node->nextNode;
if(ret!=0 ||
interface->expired) {
node = NULL;
}
}
if(strcmp(interface->buffer,
INTERFACE_LIST_MODE_END)==0)
{
DEBUG("interface %i: process command "
"list\n",interface->num);
ret = proccessListOfCommands(
interface->fp,
&(interface->permission),
&(interface->expired),
interface->commandList);
DEBUG("interface %i: process command "
"list returned %i\n",
interface->num,
ret);
if(ret==0) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
commandSuccess(interface->fp);
}
else if(ret==COMMAND_RETURN_CLOSE ||
interface->expired) {
......@@ -262,21 +248,34 @@ int interfaceReadInput(Interface * interface) {
interface->commandList = NULL;
}
else {
interface->commandListSize+=sizeof(ListNode);
interface->commandListSize+=strlen(interface->buffer)+1;
if(interface->commandListSize>interface_max_command_list_size) {
ERROR("interface %i: command list size (%lli) is larger than the max (%lli)\n",interface->num,interface->commandListSize,interface_max_command_list_size);
interface->commandListSize+=
sizeof(ListNode);
interface->commandListSize+=
strlen(interface->buffer)+1;
if(interface->commandListSize >
interface_max_command_list_size)
{
ERROR("interface %i: command "
"list size (%lli) is "
"larger than the max "
"(%lli)\n",
interface->num,
interface->
commandListSize,
interface_max_command_list_size);
closeInterface(interface);
}
else {
insertInListWithoutKey(interface->commandList,strdup(interface->buffer));
insertInListWithoutKey(
interface->commandList,
strdup(interface->
buffer));
}
}
}
else {
if(argArrayLength &&
strcmp(argArray[0],
if(strcmp(interface->buffer,
INTERFACE_LIST_MODE_BEGIN)==0)
{
interface->commandList = makeList(free);
......@@ -285,21 +284,26 @@ int interfaceReadInput(Interface * interface) {
ret = 1;
}
else {
if(argArrayLength==0) ret = 0;
else if(strcmp(argArray[0],
if(strcmp(interface->buffer,
INTERFACE_LIST_MODE_END)
==0)
{
myfprintf(interface->fp,"%s not in command list mode\n",COMMAND_RESPOND_ERROR);
commandError(interface->fp,
ACK_ERROR_NOT_LIST,
"not in command list mode");
ret = -1;
}
else {
DEBUG("interface %i: process command \"%s\"\n",interface->num,interface->buffer);
ret = processCommand(interface->fp,&(interface->permission),argArrayLength,argArray);
ret = processCommand(
interface->fp,
&(interface->
permission),
interface->buffer);
DEBUG("interface %i: command returned %i\n",interface->num,ret);
}
if(ret==0) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
commandSuccess(interface->fp);
}
else if(ret==COMMAND_RETURN_CLOSE ||
interface->expired) {
......@@ -308,7 +312,6 @@ int interfaceReadInput(Interface * interface) {
printInterfaceOutBuffer(interface);
}
}
freeArgArray(argArray,argArrayLength);
}
return ret;
}
......@@ -418,25 +421,25 @@ void initInterfaces() {
interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
if(*test!='\0' || interface_timeout<=0) {
ERROR("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]);
exit(-1);
exit(EXIT_FAILURE);
}
interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10);
if(*test!='\0' || interface_max_connections<=0) {
ERROR("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]);
exit(-1);
exit(EXIT_FAILURE);
}
interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10);
if(*test!='\0' || interface_max_command_list_size<=0) {
ERROR("max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]);
exit(-1);
exit(EXIT_FAILURE);
}
interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10);
if(*test!='\0' || interface_max_output_buffer_size<=0) {
ERROR("max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]);
exit(-1);
exit(EXIT_FAILURE);
}
interface_max_command_list_size*=1024;
......@@ -645,3 +648,4 @@ void printInterfaceOutBuffer(Interface * interface) {
interface->outBuflen = 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -38,3 +38,4 @@ int interfacePrintWithFD(int fd, char * buffer);
int doIOForInterfaces();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -914,6 +914,20 @@ case $host in
rm -rf conftest*
;;
*-*-linux*)
# Test if the compiler is 64bit
echo 'int i;' > conftest.$ac_ext
lt_cv_cc_64bit_output=no
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
*"ELF 64"*)
lt_cv_cc_64bit_output=yes
;;
esac
fi
rm -rf conftest*
;;
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
SAVE_CFLAGS="$CFLAGS"
......@@ -2191,6 +2205,30 @@ EOF
hardcode_shlibpath_var=no
;;
linux*)
if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
supports_anon_versioning=no
case `$LD -v 2>/dev/null` in
*\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
*\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
*\ 2.11.*) ;; # other 2.11 versions
*) supports_anon_versioning=yes ;;
esac
if test $supports_anon_versioning = yes; then
archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
$echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
else
$archive_expsym_cmds="$archive_cmds"
fi
else
ld_shlibs=no
fi
;;
*)
if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
......@@ -2724,8 +2762,8 @@ shlibpath_var=
shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/X11R6/lib"
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib /usr/X11R6/lib"
case $host_os in
aix3*)
......@@ -2959,6 +2997,13 @@ linux-gnu*)
# before this can be enabled.
hardcode_into_libs=yes
case $host_cpu:$lt_cv_cc_64bit_output in
powerpc64:yes | s390x:yes | sparc64:yes | x86_64:yes)
sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /usr/X11R6/lib64"
sys_lib_search_path_spec="/lib64 /usr/lib64 /usr/local/lib64 /usr/X11R6/lib64"
;;
esac
# We used to test for /lib/ld.so.1 and disable shared libraries on
# powerpc, because MkLinux only supported shared libraries with the
# GNU dynamic linker. Since this was broken with cross compilers,
......@@ -2970,7 +3015,7 @@ linux-gnu*)
# Find out which ABI we are using (multilib Linux x86_64 hack).
libsuff=
case "$host_cpu" in
x86_64*|s390x*)
x86_64*)
echo '[#]line __oline__ "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
......
......@@ -72,6 +72,8 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
......@@ -946,6 +946,20 @@ case $host in
rm -rf conftest*
;;
*-*-linux*)
# Test if the compiler is 64bit
echo 'int i;' > conftest.$ac_ext
lt_cv_cc_64bit_output=no
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
*"ELF 64"*)
lt_cv_cc_64bit_output=yes
;;
esac
fi
rm -rf conftest*
;;
*-*-sco3.2v5*)
# On SCO OpenServer 5, we need -belf to get full-featured binaries.
SAVE_CFLAGS="$CFLAGS"
......@@ -2223,6 +2237,30 @@ EOF
hardcode_shlibpath_var=no
;;
linux*)
if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
supports_anon_versioning=no
case `$LD -v 2>/dev/null` in
*\ [01].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
*\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
*\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
*\ 2.11.*) ;; # other 2.11 versions
*) supports_anon_versioning=yes ;;
esac
if test $supports_anon_versioning = yes; then
archive_expsym_cmds='$echo "{ global:" > $output_objdir/$libname.ver~
cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
$echo "local: *; };" >> $output_objdir/$libname.ver~
$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
else
$archive_expsym_cmds="$archive_cmds"
fi
else
ld_shlibs=no
fi
;;
*)
if $LD --help 2>&1 | egrep ': supported targets:.* elf' > /dev/null; then
archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
......@@ -2756,8 +2794,8 @@ shlibpath_var=
shlibpath_overrides_runpath=unknown
version_type=none
dynamic_linker="$host_os ld.so"
sys_lib_dlsearch_path_spec="/lib /usr/lib"
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
sys_lib_dlsearch_path_spec="/lib /usr/lib /usr/X11R6/lib"
sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib /usr/X11R6/lib"
case $host_os in
aix3*)
......@@ -2991,6 +3029,13 @@ linux-gnu*)
# before this can be enabled.
hardcode_into_libs=yes
case $host_cpu:$lt_cv_cc_64bit_output in
powerpc64:yes | s390x:yes | sparc64:yes | x86_64:yes)
sys_lib_dlsearch_path_spec="/lib64 /usr/lib64 /usr/X11R6/lib64"
sys_lib_search_path_spec="/lib64 /usr/lib64 /usr/local/lib64 /usr/X11R6/lib64"
;;
esac
# We used to test for /lib/ld.so.1 and disable shared libraries on
# powerpc, because MkLinux only supported shared libraries with the
# GNU dynamic linker. Since this was broken with cross compilers,
......@@ -3002,7 +3047,7 @@ linux-gnu*)
# Find out which ABI we are using (multilib Linux x86_64 hack).
libsuff=
case "$host_cpu" in
x86_64*|s390x*)
x86_64*)
echo '[#]line __oline__ "configure"' > conftest.$ac_ext
if AC_TRY_EVAL(ac_compile); then
case `/usr/bin/file conftest.$ac_objext` in
......
......@@ -125,9 +125,11 @@
/* Define to empty if `const' does not conform to ANSI C. */
#undef const
/* Define as `__inline' if that's what the C compiler calls it, or to nothing
if it is not supported. */
/* Define to `__inline__' or `__inline' if that's what the C compiler
calls it, or to nothing if 'inline' is not supported under any name. */
#ifndef __cplusplus
#undef inline
#endif
/* Define to `int' if <sys/types.h> does not define. */
#undef pid_t
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -24,12 +24,12 @@
extern "C" {
# endif
# define FPM_INTEL
# define FPM_DEFAULT
# define SIZEOF_INT 4
# define SIZEOF_LONG 4
# define SIZEOF_LONG 8
# define SIZEOF_LONG_LONG 8
......
......@@ -56,6 +56,54 @@ List * makeList(ListFreeDataFunc * freeDataFunc) {
return list;
}
int insertInListBeforeNode(List * list, ListNode * beforeNode, char * key,
void * data)
{
ListNode * node;
assert(list!=NULL);
assert(key!=NULL);
/*assert(data!=NULL);*/
node = malloc(sizeof(ListNode));
assert(node!=NULL);
if(list->nodesArray) freeListNodesArray(list);
if(beforeNode==NULL) beforeNode = list->firstNode;
node->nextNode = beforeNode;
if(beforeNode==list->firstNode) {
if(list->firstNode==NULL) {
assert(list->lastNode==NULL);
list->lastNode = node;
}
else {
assert(list->lastNode!=NULL);
assert(list->lastNode->nextNode==NULL);
list->firstNode->prevNode = node;
}
node->prevNode = NULL;
list->firstNode = node;
}
else {
node->prevNode = beforeNode->prevNode;
if(node->prevNode) {
node->prevNode->nextNode = node;
}
beforeNode->prevNode = node;
}
node->key = malloc((strlen(key)+1)*sizeof(char));
assert(node->key!=NULL);
strcpy(node->key,key);
node->data = data;
list->numberOfNodes++;
return 1;
}
int insertInList(List * list,char * key,void * data) {
ListNode * node;
......@@ -434,3 +482,4 @@ void sortList(List * list) {
quickSort(list->nodesArray,0,list->numberOfNodes-1);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -69,6 +69,9 @@ List * makeList(ListFreeDataFunc * freeDataFunc);
*/
int insertInList(List * list,char * key,void * data);
int insertInListBeforeNode(List * list, ListNode * beforeNode, char * key,
void * data);
int insertInListWithoutKey(List * list,void * data);
/* deletes the first node in the list with the key _key_
......@@ -99,3 +102,4 @@ void clearList(List * list);
void sortList(List * list);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -20,6 +20,7 @@
#include "interface.h"
#include "conf.h"
#include "log.h"
#include "utils.h"
#include <unistd.h>
#include <stdio.h>
......@@ -42,16 +43,6 @@
int listenSocket;
#ifdef HAVE_IPV6
int ipv6Supported() {
int s;
s = socket(AF_INET6,SOCK_STREAM,0);
if(s == -1) return 0;
close(s);
return 1;
}
#endif
int establish(unsigned short port) {
int allowReuse = ALLOW_REUSE;
int sock;
......@@ -90,7 +81,7 @@ int establish(unsigned short port) {
if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) {
ERROR("can't lookup host \"%s\"\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
exit(EXIT_FAILURE);
}
switch(he->h_addrtype) {
#ifdef HAVE_IPV6
......@@ -99,7 +90,7 @@ int establish(unsigned short port) {
ERROR("no IPv6 support, but a IPv6 address "
"found for \"%s\"\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
exit(EXIT_FAILURE);
}
bcopy((char *)he->h_addr,(char *)
&sin6.sin6_addr.s6_addr,he->h_length);
......@@ -116,7 +107,7 @@ int establish(unsigned short port) {
default:
ERROR("address type for \"%s\" is not IPv4 or IPv6\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
exit(EXIT_FAILURE);
}
}
......@@ -184,3 +175,4 @@ void getConnections(int sock) {
}
else if(fd<0) ERROR("Problems accept()'ing\n");
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -28,3 +28,4 @@ int establish(unsigned short port);
void getConnections(int sock);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -37,3 +37,4 @@ void initLog() {
}
else ERROR("unknown log level \"%s\"\n",getConf()[CONF_LOG_LEVEL]);
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -29,17 +29,18 @@
extern int logLevel;
#define ERROR(x, arg...) myfprintf(stderr, x , ##arg)
#define ERROR(...) myfprintf(stderr, __VA_ARGS__)
#define LOG(x, arg...) myfprintf(stdout, x , ##arg)
#define LOG(...) myfprintf(stdout, __VA_ARGS__)
#define SECURE(x, arg...) if(logLevel>=LOG_LEVEL_SECURE) \
myfprintf(stdout, x , ##arg)
#define SECURE(...) if(logLevel>=LOG_LEVEL_SECURE) \
myfprintf(stdout, __VA_ARGS__)
#define DEBUG(x, arg...) if(logLevel>=LOG_LEVEL_DEBUG) \
myfprintf(stdout, x , ##arg)
#define DEBUG(...) if(logLevel>=LOG_LEVEL_DEBUG) \
myfprintf(stdout, __VA_ARGS__)
void initLog();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -17,11 +17,11 @@
*/
#include "ls.h"
#include "command.h"
#include "playlist.h"
#include "path.h"
#include "myfprintf.h"
#include "log.h"
#include "utf8.h"
#include <sys/types.h>
#include <sys/stat.h>
......@@ -41,11 +41,87 @@ char * dupAndStripPlaylistSuffix(char * file) {
return ret;
}
static char * remoteUrlPrefixes[] =
{
"http://",
NULL
};
int printRemoteUrlHandlers(FILE * fp) {
char ** prefixes = remoteUrlPrefixes;
while (*prefixes) {
myfprintf(fp,"handler: %s\n", *prefixes);
prefixes++;
}
return 0;
}
int isValidRemoteUtf8Url(char * utf8url) {
int ret = 0;
char * temp;
switch(isRemoteUrl(utf8url)) {
case 1:
ret = 1;
temp = utf8url;
while(*temp) {
if((*temp >= 'a' && *temp <= 'z') ||
(*temp >= 'A' && *temp <= 'z') ||
(*temp >= '0' && *temp <= '9') ||
*temp == '$' ||
*temp == '-' ||
*temp == '.' ||
*temp == '+' ||
*temp == '!' ||
*temp == '*' ||
*temp == '\'' ||
*temp == '(' ||
*temp == ')' ||
*temp == ',' ||
*temp == '%' ||
*temp == '/' ||
*temp == ':' ||
*temp == '?' ||
*temp == ';' ||
*temp == '&' ||
*temp == '=')
{
}
else {
ret = 1;
break;
}
temp++;
}
break;
}
return ret;
}
int isRemoteUrl(char * url) {
int count = 0;
char ** urlPrefixes = remoteUrlPrefixes;
while(*urlPrefixes) {
count++;
if(strncmp(*urlPrefixes,url,strlen(*urlPrefixes)) == 0) {
return count;
}
urlPrefixes++;
}
return 0;
}
int lsPlaylists(FILE * fp, char * utf8path) {
DIR * dir;
struct stat st;
struct dirent * ent;
char * dup;
char * utf8;
char s[MAXPATHLEN+1];
List * list = NULL;
ListNode * node = NULL;
......@@ -62,6 +138,7 @@ int lsPlaylists(FILE * fp, char * utf8path) {
}
s[MAXPATHLEN] = '\0';
/* this is safe, notice actlen > MAXPATHLEN-1 above */
strcpy(s,actualPath);
strcat(s,"/");
......@@ -78,8 +155,9 @@ int lsPlaylists(FILE * fp, char * utf8path) {
if(list==NULL) list = makeList(NULL);
dup = strdup(ent->d_name);
dup[suff] = '\0';
insertInList(list,
fsCharsetToUtf8(dup),NULL);
if((utf8 = fsCharsetToUtf8(dup))) {
insertInList(list,utf8,NULL);
}
free(dup);
}
}
......@@ -99,7 +177,9 @@ int lsPlaylists(FILE * fp, char * utf8path) {
node = list->firstNode;
while(node!=NULL) {
myfprintf(fp,"playlist: %s%s\n",dup,node->key);
if(!strchr(node->key, '\n')) {
myfprintf(fp,"playlist: %s%s\n",dup,node->key);
}
node = node->nextNode;
}
......@@ -128,22 +208,24 @@ int isFile(char * utf8file, time_t * mtime) {
return 0;
}
int hasSuffix(char * utf8file, char * suffix) {
char * file = utf8ToFsCharset(utf8file);
char * dup = strdup(file);
char * cLast;
char * cNext;
int ret = 0;
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcasecmp(cLast,suffix)) ret = 1;
free(dup);
/* suffixes should be ascii only characters */
char * getSuffix(char * utf8file) {
char * ret = NULL;
while(*utf8file) {
if(*utf8file == '.') ret = utf8file+1;
utf8file++;
}
return ret;
}
int hasSuffix(char * utf8file, char * suffix) {
char * s = getSuffix(utf8file);
if(s && 0==strcmp(s,suffix)) return 1;
return 0;
}
int isPlaylist(char * utf8file) {
if(isFile(utf8file,NULL)) {
return hasSuffix(utf8file,PLAYLIST_FILE_SUFFIX);
......@@ -177,12 +259,11 @@ int hasMp3Suffix(char * utf8file) {
return hasSuffix(utf8file,"mp3");
}
int isDir(char * utf8name, time_t * mtime) {
int isDir(char * utf8name) {
struct stat st;
if(stat(rmp2amp(utf8ToFsCharset(utf8name)),&st)==0) {
if(S_ISDIR(st.st_mode)) {
if(mtime) *mtime = st.st_mtime;
return 1;
}
}
......@@ -194,26 +275,15 @@ int isDir(char * utf8name, time_t * mtime) {
return 0;
}
int isMusic(char * utf8file, time_t * mtime) {
InputPlugin * isMusic(char * utf8file, time_t * mtime) {
InputPlugin * ret = NULL;
if(isFile(utf8file,mtime)) {
#ifdef HAVE_OGG
if(hasOggSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_FLAC
if(hasFlacSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_MAD
if(hasMp3Suffix(utf8file)) return 1;
#endif
#ifdef HAVE_AUDIOFILE
if(hasWaveSuffix(utf8file)) return 1;
#endif
#ifdef HAVE_FAAD
if(hasMp4Suffix(utf8file)) return 1;
if(hasAacSuffix(utf8file)) return 1;
#endif
char * s = getSuffix(utf8file);
if(s) ret = getInputPluginFromSuffix(s);
}
return 0;
return ret;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -21,31 +21,30 @@
#include "../config.h"
#include "inputPlugin.h"
#include <stdio.h>
#include <time.h>
int lsPlaylists(FILE * fp, char * utf8path);
int isFile(char * utf8file, time_t * mtime);
int isDir(char * utf8name, time_t * mtime);
int isPlaylist(char * utf8file);
char * getSuffix(char * utf8file);
int isMusic(char * utf8file, time_t * mtime);
int isValidRemoteUtf8Url(char * utf8url);
int hasWaveSuffix(char * utf8file);
int isRemoteUrl(char * url);
int hasMp3Suffix(char * utf8file);
int hasAacSuffix(char * utf8file);
int isFile(char * utf8file, time_t * mtime);
int hasMp4Suffix(char * utf8file);
int isDir(char * utf8name);
int hasOggSuffix(char * utf8file);
int isPlaylist(char * utf8file);
int hasFlacSuffix(char * utf8file);
InputPlugin * isMusic(char * utf8file, time_t * mtime);
char * dupAndStripPlaylistSuffix(char * file);
int printRemoteUrlHandlers(FILE * fp);
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#ifndef MP4_DECODE_H
#define MP4_DECODE_H
#include "../config.h"
#ifdef HAVE_FAAD
#include "playerData.h"
#include "mp4ff/mp4ff.h"
int mp4_getAACTrack(mp4ff_t *infile);
uint32_t mp4_readCallback(void *user_data, void *buffer, uint32_t length);
uint32_t mp4_seekCallback(void *user_data, uint64_t position);
int mp4_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif /* HAVE_FAAD */
#endif
......@@ -84,6 +84,10 @@ ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBMIKMOD_CFLAGS = @LIBMIKMOD_CFLAGS@
LIBMIKMOD_CONFIG = @LIBMIKMOD_CONFIG@
LIBMIKMOD_LDADD = @LIBMIKMOD_LDADD@
LIBMIKMOD_LIBS = @LIBMIKMOD_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
......
......@@ -41,3 +41,4 @@ typedef signed long mpd_sint32;
#endif
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -18,6 +18,8 @@
#include "myfprintf.h"
#include "interface.h"
#include "path.h"
#include "log.h"
#include <stdarg.h>
#include <sys/param.h>
......@@ -32,39 +34,93 @@
int myfprintf_stdLogMode = 0;
FILE * myfprintf_out;
FILE * myfprintf_err;
char * myfprintf_outFilename;
char * myfprintf_errFilename;
void myfprintfStdLogMode(FILE * out, FILE * err) {
void blockingWrite(int fd, char * string) {
int len = strlen(string);
int ret;
while(len) {
ret = write(fd,string,len);
if(ret<0) {
switch(errno) {
case EAGAIN:
case EINTR:
continue;
default:
return;
}
}
len-= ret;
string+= ret;
}
}
void myfprintfStdLogMode(FILE * out, FILE * err, char * outFilename,
char * errFilename)
{
myfprintf_stdLogMode = 1;
myfprintf_out = out;
myfprintf_err = err;
myfprintf_outFilename = prependCwdToPathDup(outFilename);
myfprintf_errFilename = prependCwdToPathDup(errFilename);
}
void myfprintf(FILE * fp, char * format, ... ) {
char buffer[BUFFER_LENGTH+1];
va_list arglist;
int fd = fileno(fp);
int fcntlret;
memset(buffer,0,BUFFER_LENGTH+1);
va_start(arglist,format);
while((fcntlret=fcntl(fd,F_GETFL))==-1 && errno==EINTR);
if(myfprintf_stdLogMode && (fd==1 || fd==2)) {
char str[15];
time_t t = time(NULL);
if(fd==1) fp = myfprintf_out;
else fp = myfprintf_err;
strftime(str,14,"%b %e %R",localtime(&t));
fprintf(fp,"%s : ",str);
vfprintf(fp,format,arglist);
strftime(buffer,14,"%b %e %R",localtime(&t));
blockingWrite(fd,buffer);
blockingWrite(fd," : ");
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
blockingWrite(fd,buffer);
}
else if(fcntlret & O_NONBLOCK) {
char buffer[BUFFER_LENGTH+1];
else {
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
if(interfacePrintWithFD(fd,buffer)<0) {
/* not a fd from a interface */
vfprintf(fp,format,arglist);
if(!(fcntlret & O_NONBLOCK) ||
interfacePrintWithFD(fd,buffer)<0)
{
blockingWrite(fd,buffer);
}
}
else vfprintf(fp,format,arglist);
fflush(fp);
va_end(arglist);
}
int myfprintfCloseAndOpenLogFile() {
if(myfprintf_stdLogMode) {
while(fclose(myfprintf_out)<0 && errno==EINTR);
while(fclose(myfprintf_err)<0 && errno==EINTR);
while((myfprintf_out = fopen(myfprintf_outFilename,"a+"))==NULL
&& errno==EINTR);
if(!myfprintf_out) {
ERROR("error re-opening log file: %s\n",
myfprintf_out);
return -1;
}
while((myfprintf_err = fopen(myfprintf_errFilename,"a+"))==NULL
&& errno==EINTR);
if(!myfprintf_out) {
ERROR("error re-opening log file: %s\n",
myfprintf_out);
return -1;
}
while(dup2(fileno(myfprintf_out),1)<0 && errno==EINTR);
while(dup2(fileno(myfprintf_err),2)<0 && errno==EINTR);
}
return 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
......@@ -23,8 +23,12 @@
#include <stdio.h>
void myfprintfStdLogMode(FILE * out, FILE * err);
void myfprintfStdLogMode(FILE * out, FILE * err, char * outFilename,
char * errFilename);
void myfprintf(FILE * fp, char * format, ... );
int myfprintfCloseAndOpenLogFile();
#endif
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "ogg_decode.h"
#ifdef HAVE_OGG
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include "pcm_utils.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/vorbisfile.h>
#ifdef WORDS_BIGENDIAN
#define OGG_DECODE_USE_BIGENDIAN 1
#else
#define OGG_DECODE_USE_BIGENDIAN 0
#endif
int getOggTotalTime(char * file) {
OggVorbis_File vf;
FILE * oggfp;
int totalTime;
if(!(oggfp = fopen(file,"r"))) return -1;
if(ov_open(oggfp, &vf, NULL, 0) < 0) {
fclose(oggfp);
return -1;
}
totalTime = ov_time_total(&vf,-1)+0.5;
ov_clear(&vf);
return totalTime;
}
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
{
OggVorbis_File vf;
FILE * oggfp;
if(!(oggfp = fopen(dc->file,"r"))) {
ERROR("failed to open ogg\n");
return -1;
}
if(ov_open(oggfp, &vf, NULL, 0) < 0) {
ERROR("Input does not appear to be an Ogg bit stream.\n");
fclose(oggfp);
return -1;
}
{
vorbis_info *vi=ov_info(&vf,-1);
af->bits = 16;
af->channels = vi->channels;
af->sampleRate = vi->rate;
}
cb->totalTime = ov_time_total(&vf,-1);
dc->state = DECODE_STATE_DECODE;
dc->start = 0;
{
int current_section;
int eof = 0;
long ret;
char chunk[CHUNK_SIZE];
int chunkpos = 0;
long bitRate = 0;
long test;
while(!eof) {
if(dc->seek) {
cb->end = cb->begin;
cb->wrap = 0;
chunkpos = 0;
ov_time_seek_page(&vf,dc->seekWhere);
dc->seek = 0;
}
ret = ov_read(&vf,chunk+chunkpos,
CHUNK_SIZE-chunkpos,
OGG_DECODE_USE_BIGENDIAN,
2,1,
&current_section);
if(ret<=0) eof = 1;
else chunkpos+=ret;
if(chunkpos>=CHUNK_SIZE || eof) {
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
my_usleep(10000);
}
if(dc->stop) break;
else if(dc->seek) continue;
memcpy(cb->chunks+cb->end*CHUNK_SIZE,
chunk,chunkpos);
cb->chunkSize[cb->end] = chunkpos;
chunkpos = 0;
cb->times[cb->end] = ov_time_tell(&vf);
if((test = ov_bitrate_instant(&vf))>0) {
bitRate = test/1024;
}
cb->bitRate[cb->end] = bitRate;
cb->end++;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
}
}
ov_clear(&vf);
if(dc->seek) dc->seek = 0;
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
}
return 0;
}
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* This project's homepage is: http://www.musicpd.org
*
* 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
*/
#include "outputBuffer.h"
#include "pcm_utils.h"
#include "playerData.h"
#include "utils.h"
#include <string.h>
static mpd_sint16 currentChunk = -1;
void clearOutputBuffer(OutputBuffer * cb) {
currentChunk = -1;
cb->end = cb->begin;
cb->wrap = 0;
}
void flushOutputBuffer(OutputBuffer * cb) {
if(currentChunk == cb->end) {
cb->end++;
if(cb->end>=buffered_chunks) {
cb->end = 0;
cb->wrap = 1;
}
currentChunk = -1;
}
}
int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
DecoderControl * dc, int seekable, char * dataIn,
long dataInLen, float time, mpd_uint16 bitRate)
{
mpd_uint16 dataToSend;
mpd_uint16 chunkLeft;
char * data;
size_t datalen;
static char * convBuffer = NULL;
static long convBufferLen = 0;
if(memcmp(&(cb->audioFormat),&(dc->audioFormat),sizeof(AudioFormat))==0)
{
data = dataIn;
datalen = dataInLen;
}
else {
datalen = pcm_sizeOfOutputBufferForAudioFormatConversion(
&(dc->audioFormat), dataIn, dataInLen,
&(cb->audioFormat));
if(datalen > convBufferLen) {
convBuffer = realloc(convBuffer,datalen);
convBufferLen = datalen;
}
data = convBuffer;
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
&(cb->audioFormat),data);
}
while(datalen) {
if(currentChunk != cb->end) {
while(cb->begin==cb->end && cb->wrap && !dc->stop)
{
if(dc->seek) {
if(seekable) {
return OUTPUT_BUFFER_DC_SEEK;
}
else {
dc->seekError = 1;
dc->seek = 0;
}
}
if(!inStream ||
bufferInputStream(inStream) <= 0)
{
my_usleep(10000);
}
}
if(dc->stop) return OUTPUT_BUFFER_DC_STOP;
currentChunk = cb->end;
cb->chunkSize[currentChunk] = 0;
}
chunkLeft = CHUNK_SIZE-cb->chunkSize[currentChunk];
dataToSend = datalen > chunkLeft ? chunkLeft : datalen;
memcpy(cb->chunks+currentChunk*CHUNK_SIZE+
cb->chunkSize[currentChunk],
data, dataToSend);
cb->chunkSize[currentChunk]+= dataToSend;
cb->bitRate[currentChunk] = bitRate;
cb->times[currentChunk] = time;
datalen-= dataToSend;
data+= dataToSend;
if(cb->chunkSize[currentChunk] == CHUNK_SIZE) {
flushOutputBuffer(cb);
}
}
return 0;
}
/* vim:set shiftwidth=4 tabstop=8 expandtab: */
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment