Commit f0be54b6 authored by Led's avatar Led

0.9.0

parent 80d767ba
ver 0.9.0 (2003/9/30)
1) Random play mode
2) Alsa Mixer Support
3) Save and Restore "state"
4) Default config file locations (.mpdconf and /etc/mpd.conf)
5) Make db file locations configurable
6) Move songs around in the playlist
7) Gapless playback
8) Use Xing tags for mp3's
9) Remove stop_on_error
10) Seeking support
11) Playlists can be loaded and deleted from subdirectories
12) Complete rewrite of player layer (fork()'s only once, opens and closes
audio device as needed).
13) Eliminate use and dependence of SIGIO
14) IPv6 support
15) Solaris compilations fixes
16) Support for different log levels
17) Timestamps for log entries
18) "user" config parameter for setuid (patch from Nagilum)
19) Other misc features and bug fixes
ver 0.8.7 (2003/9/3) ver 0.8.7 (2003/9/3)
1) Fix a memory leak. When closing a interface, was called close() on the fd 1) Fix a memory leak. When closing a interface, was called close() on the fd
instead of calling fclose() on the fp that was opened with fdopen(). instead of calling fclose() on the fp that was opened with fdopen().
......
...@@ -6,20 +6,20 @@ Requirements ...@@ -6,20 +6,20 @@ Requirements
libao - http://www.vorbis.com/download_unix.psp libao - http://www.vorbis.com/download_unix.psp
(This comes with most/all distributions. Make sure you have both (This comes with most/all distributions. Make sure you have both
the ao libs and development packages for your distribution installed. the ao libs and development packages for your distribution installed.
For Red Hat 8.0, the neccessary packages are: libao and libao-devel) For Red Hat 8.0, the necessary packages are: libao and libao-devel)
zlib - http://www.gzip.org/zlib zlib - http://www.gzip.org/zlib
(This comes with all distributions. Make sure you have bot the zlib libs (This comes with all distributions. Make sure you have bot the zlib libs
and development packages for your distribution installed. For Red hat, and development packages for your distribution installed. For Red hat,
the neccessary packages are: zlib and zlib-devel) the necessary packages are: zlib and zlib-devel)
Optional Optional
-------- --------
Ogg Vorbis - http://www.xiph.org/ogg/vorbis/ Ogg Vorbis - http://www.xiph.org/ogg/vorbis/
(This comes with most/all distrobutions. Make sure you have both the (This comes with most/all distributions. Make sure you have both the
ogg and vorbis libs as well as the development packages for your ogg and vorbis libs as well as the development packages for your
distrobution installed. For Red Hat 8.0, the neccessary packages are: distribution installed. For Red Hat 8.0, the necessary packages are:
libogg, libogg-devel, libvorbis, and libvorbis-devel). libogg, libogg-devel, libvorbis, and libvorbis-devel).
Flac - http://flac.sf.net Flac - http://flac.sf.net
...@@ -33,7 +33,7 @@ Get the latest release from of MPD from http://www.musicpd.org ...@@ -33,7 +33,7 @@ Get the latest release from of MPD from http://www.musicpd.org
Compile Compile
------- -------
1) unzip and untar the argchive 1) unzip and untar the archive
$ tar zxvf mpd-x.x.x.tar.gz $ tar zxvf mpd-x.x.x.tar.gz
...@@ -80,6 +80,8 @@ run mpd like this: ...@@ -80,6 +80,8 @@ run mpd like this:
$ mpd <config file> $ mpd <config file>
(if no config file is specified, mpd's looks for ~/.mpdconf then /etc/mpd.conf)
an example would be: an example would be:
$ mpd playlists/.mpdconf $ mpd playlists/.mpdconf
...@@ -92,4 +94,6 @@ Using MPD ...@@ -92,4 +94,6 @@ Using MPD
You can download a web interface (phpMp) to MPD at You can download a web interface (phpMp) to MPD at
http://www.musicpd.org . http://www.musicpd.org .
Also, several other clients can be found for MPD at http://www.musicpd.org .
MPD can be interfaced directly using telnet (see COMMANDS, if you are brave). MPD can be interfaced directly using telnet (see COMMANDS, if you are brave).
bin_PROGRAMS = mpd SUBDIRS = src doc debian
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
man_MANS = mpd.1
pkgdata_DATA =
docdir = $(prefix)/share/doc/$(PACKAGE) docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING doc_DATA = README UPGRADING
EXTRA_DIST = mpdconf.example COMMANDS COPYING $(pkgdata_DATA) $(man_MANS) $(doc_DATA) EXTRA_DIST = COPYING $(doc_DATA)
mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
song.h list.h directory.h tables.h utils.h path.h flac_decode.h \
tag.h player.h listen.h conf.h ogg_decode.h volume.h mp3_decode.h \
audio.h buffer.h stats.h myfprintf.h sig_handlers.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 flac_decode.c\
tag.c player.c listen.c conf.c ogg_decode.c volume.c mp3_decode.c \
audio.c buffer.c stats.c myfprintf.c sig_handlers.c $(mpd_headers)
CFLAGS = @CFLAGS@ $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB)
...@@ -68,14 +68,21 @@ PATH_SEPARATOR = @PATH_SEPARATOR@ ...@@ -68,14 +68,21 @@ PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@ AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@ AO_LIBS = @AO_LIBS@
AR = @AR@
AS = @AS@ AS = @AS@
AWK = @AWK@ AWK = @AWK@
CC = @CC@ CC = @CC@
CCAS = @CCAS@ CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@ CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@ DLLTOOL = @DLLTOOL@
ECHO = @ECHO@ ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
ID3_LIB = @ID3_LIB@ ID3_LIB = @ID3_LIB@
ID3_SUBDIR = @ID3_SUBDIR@ ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
...@@ -92,6 +99,7 @@ OGG_CFLAGS = @OGG_CFLAGS@ ...@@ -92,6 +99,7 @@ OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@ OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@ STRIP = @STRIP@
VERSION = @VERSION@ VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@ VORBISENC_LIBS = @VORBISENC_LIBS@
...@@ -101,79 +109,16 @@ VORBIS_LIBS = @VORBIS_LIBS@ ...@@ -101,79 +109,16 @@ VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@ am__include = @am__include@
am__quote = @am__quote@ am__quote = @am__quote@
install_sh = @install_sh@ install_sh = @install_sh@
bin_PROGRAMS = mpd SUBDIRS = src doc debian
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
man_MANS = mpd.1
pkgdata_DATA =
docdir = $(prefix)/share/doc/$(PACKAGE) docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING doc_DATA = README UPGRADING
EXTRA_DIST = mpdconf.example COMMANDS COPYING $(pkgdata_DATA) $(man_MANS) $(doc_DATA) EXTRA_DIST = COPYING $(doc_DATA)
mpd_headers = buffer2array.h interface.h command.h playlist.h ls.h \
song.h list.h directory.h tables.h utils.h path.h flac_decode.h \
tag.h player.h listen.h conf.h ogg_decode.h volume.h mp3_decode.h \
audio.h buffer.h stats.h myfprintf.h sig_handlers.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 flac_decode.c\
tag.c player.c listen.c conf.c ogg_decode.c volume.c mp3_decode.c \
audio.c buffer.c stats.c myfprintf.c sig_handlers.c $(mpd_headers)
CFLAGS = @CFLAGS@ $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB)
subdir = . subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES = CONFIG_CLEAN_FILES =
bin_PROGRAMS = mpd$(EXEEXT) DIST_SOURCES =
PROGRAMS = $(bin_PROGRAMS) DATA = $(doc_DATA)
am__objects_1 =
am_mpd_OBJECTS = main.$(OBJEXT) buffer2array.$(OBJEXT) \
interface.$(OBJEXT) command.$(OBJEXT) playlist.$(OBJEXT) \
ls.$(OBJEXT) song.$(OBJEXT) list.$(OBJEXT) directory.$(OBJEXT) \
tables.$(OBJEXT) utils.$(OBJEXT) path.$(OBJEXT) \
flac_decode.$(OBJEXT) tag.$(OBJEXT) player.$(OBJEXT) \
listen.$(OBJEXT) conf.$(OBJEXT) ogg_decode.$(OBJEXT) \
volume.$(OBJEXT) mp3_decode.$(OBJEXT) audio.$(OBJEXT) \
buffer.$(OBJEXT) stats.$(OBJEXT) myfprintf.$(OBJEXT) \
sig_handlers.$(OBJEXT) $(am__objects_1)
mpd_OBJECTS = $(am_mpd_OBJECTS)
mpd_DEPENDENCIES =
mpd_LDFLAGS =
DEFS = @DEFS@
DEFAULT_INCLUDES = -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/audio.Po ./$(DEPDIR)/buffer.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/buffer2array.Po ./$(DEPDIR)/command.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/conf.Po ./$(DEPDIR)/directory.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/flac_decode.Po ./$(DEPDIR)/interface.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/list.Po ./$(DEPDIR)/listen.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/ls.Po ./$(DEPDIR)/main.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/mp3_decode.Po ./$(DEPDIR)/myfprintf.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/ogg_decode.Po ./$(DEPDIR)/path.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/player.Po ./$(DEPDIR)/playlist.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sig_handlers.Po ./$(DEPDIR)/song.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/stats.Po ./$(DEPDIR)/tables.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/tag.Po ./$(DEPDIR)/utils.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/volume.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
$(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(mpd_SOURCES)
NROFF = nroff
MANS = $(man_MANS)
DATA = $(doc_DATA) $(pkgdata_DATA)
RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
...@@ -184,12 +129,9 @@ DIST_COMMON = README COPYING ChangeLog INSTALL Makefile.am Makefile.in \ ...@@ -184,12 +129,9 @@ DIST_COMMON = README COPYING ChangeLog INSTALL Makefile.am Makefile.in \
TODO aclocal.m4 config.guess config.sub configure configure.in \ TODO aclocal.m4 config.guess config.sub configure configure.in \
depcomp install-sh ltmain.sh missing mkinstalldirs depcomp install-sh ltmain.sh missing mkinstalldirs
DIST_SUBDIRS = $(SUBDIRS) DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(mpd_SOURCES)
all: all-recursive all: all-recursive
.SUFFIXES: .SUFFIXES:
.SUFFIXES: .c .lo .o .obj
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno configure.lineno
...@@ -206,92 +148,6 @@ $(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENC ...@@ -206,92 +148,6 @@ $(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENC
$(ACLOCAL_M4): configure.in $(ACLOCAL_M4): configure.in
cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS) cd $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
|| test -f $$p1 \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
rm -f $(DESTDIR)$(bindir)/$$f; \
done
clean-binPROGRAMS:
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
done
mpd$(EXEEXT): $(mpd_OBJECTS) $(mpd_DEPENDENCIES)
@rm -f mpd$(EXEEXT)
$(LINK) $(mpd_LDFLAGS) $(mpd_OBJECTS) $(mpd_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT) core *.core
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer2array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/directory.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flac_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp3_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myfprintf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/player.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playlist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sig_handlers.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/song.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/volume.Po@am__quote@
distclean-depend:
-rm -rf ./$(DEPDIR)
.c.o:
@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
.c.obj:
@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(COMPILE) -c `cygpath -w $<`
.c.lo:
@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
CCDEPMODE = @CCDEPMODE@
mostlyclean-libtool: mostlyclean-libtool:
-rm -f *.lo -rm -f *.lo
...@@ -302,49 +158,6 @@ clean-libtool: ...@@ -302,49 +158,6 @@ clean-libtool:
distclean-libtool: distclean-libtool:
-rm -f libtool -rm -f libtool
uninstall-info-am: uninstall-info-am:
man1dir = $(mandir)/man1
install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(man1dir)
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
1*) ;; \
*) ext='1' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
done
uninstall-man1:
@$(NORMAL_UNINSTALL)
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
rm -f $(DESTDIR)$(man1dir)/$$inst; \
done
docDATA_INSTALL = $(INSTALL_DATA) docDATA_INSTALL = $(INSTALL_DATA)
install-docDATA: $(doc_DATA) install-docDATA: $(doc_DATA)
@$(NORMAL_INSTALL) @$(NORMAL_INSTALL)
...@@ -363,24 +176,6 @@ uninstall-docDATA: ...@@ -363,24 +176,6 @@ uninstall-docDATA:
echo " rm -f $(DESTDIR)$(docdir)/$$f"; \ echo " rm -f $(DESTDIR)$(docdir)/$$f"; \
rm -f $(DESTDIR)$(docdir)/$$f; \ rm -f $(DESTDIR)$(docdir)/$$f; \
done done
pkgdataDATA_INSTALL = $(INSTALL_DATA)
install-pkgdataDATA: $(pkgdata_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(pkgdatadir)
@list='$(pkgdata_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(pkgdataDATA_INSTALL) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f"; \
$(pkgdataDATA_INSTALL) $$d$$p $(DESTDIR)$(pkgdatadir)/$$f; \
done
uninstall-pkgdataDATA:
@$(NORMAL_UNINSTALL)
@list='$(pkgdata_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(pkgdatadir)/$$f"; \
rm -f $(DESTDIR)$(pkgdatadir)/$$f; \
done
# This directory's subdirectories are mostly independent; you can cd # This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile. # into them and run `make' without going through this Makefile.
...@@ -580,10 +375,10 @@ distcleancheck: distclean ...@@ -580,10 +375,10 @@ distcleancheck: distclean
exit 1; } >&2 exit 1; } >&2
check-am: all-am check-am: all-am
check: check-recursive check: check-recursive
all-am: Makefile $(PROGRAMS) $(MANS) $(DATA) all-am: Makefile $(DATA)
installdirs: installdirs-recursive installdirs: installdirs-recursive
installdirs-am: installdirs-am:
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) $(DESTDIR)$(docdir) $(DESTDIR)$(pkgdatadir) $(mkinstalldirs) $(DESTDIR)$(docdir)
install: install-recursive install: install-recursive
install-exec: install-exec-recursive install-exec: install-exec-recursive
...@@ -611,12 +406,12 @@ maintainer-clean-generic: ...@@ -611,12 +406,12 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild." @echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive clean: clean-recursive
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES) -rm -f $(am__CONFIG_DISTCLEAN_FILES)
distclean-am: clean-am distclean-compile distclean-depend \ distclean-am: clean-am distclean-generic distclean-libtool \
distclean-generic distclean-libtool distclean-tags distclean-tags
dvi: dvi-recursive dvi: dvi-recursive
...@@ -626,13 +421,13 @@ info: info-recursive ...@@ -626,13 +421,13 @@ info: info-recursive
info-am: info-am:
install-data-am: install-docDATA install-man install-pkgdataDATA install-data-am: install-docDATA
install-exec-am: install-binPROGRAMS install-exec-am:
install-info: install-info-recursive install-info: install-info-recursive
install-man: install-man1 install-man:
installcheck-am: installcheck-am:
...@@ -643,35 +438,28 @@ maintainer-clean-am: distclean-am maintainer-clean-generic ...@@ -643,35 +438,28 @@ maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic \ mostlyclean-am: mostlyclean-generic mostlyclean-libtool
mostlyclean-libtool
uninstall-am: uninstall-binPROGRAMS uninstall-docDATA uninstall-info-am \ uninstall-am: uninstall-docDATA uninstall-info-am
uninstall-man uninstall-pkgdataDATA
uninstall-info: uninstall-info-recursive uninstall-info: uninstall-info-recursive
uninstall-man: uninstall-man1
.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \ .PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool clean-recursive \ clean-generic clean-libtool clean-recursive dist dist-all \
dist dist-all dist-gzip distcheck distclean distclean-compile \ dist-gzip distcheck distclean distclean-generic \
distclean-depend distclean-generic distclean-libtool \ distclean-libtool distclean-recursive distclean-tags \
distclean-recursive distclean-tags distcleancheck distdir dvi \ distcleancheck distdir dvi dvi-am dvi-recursive info info-am \
dvi-am dvi-recursive info info-am info-recursive install \ info-recursive install install-am install-data install-data-am \
install-am install-binPROGRAMS install-data install-data-am \
install-data-recursive install-docDATA install-exec \ install-data-recursive install-docDATA install-exec \
install-exec-am install-exec-recursive install-info \ install-exec-am install-exec-recursive install-info \
install-info-am install-info-recursive install-man install-man1 \ install-info-am install-info-recursive install-man \
install-pkgdataDATA install-recursive install-strip \ install-recursive install-strip installcheck installcheck-am \
installcheck installcheck-am installdirs installdirs-am \ installdirs installdirs-am installdirs-recursive \
installdirs-recursive maintainer-clean maintainer-clean-generic \ maintainer-clean maintainer-clean-generic \
maintainer-clean-recursive mostlyclean mostlyclean-compile \ maintainer-clean-recursive mostlyclean mostlyclean-generic \
mostlyclean-generic mostlyclean-libtool mostlyclean-recursive \ mostlyclean-libtool mostlyclean-recursive tags tags-recursive \
tags tags-recursive uninstall uninstall-am \ uninstall uninstall-am uninstall-docDATA uninstall-info-am \
uninstall-binPROGRAMS uninstall-docDATA uninstall-info-am \ uninstall-info-recursive uninstall-recursive
uninstall-info-recursive uninstall-man uninstall-man1 \
uninstall-pkgdataDATA uninstall-recursive
# Tell versions [3.59,3.63) of GNU make to not export all variables. # Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded. # Otherwise a system limit (for SysV at least) may be exceeded.
......
0.10.0
------
1) store song times (possibly after playing) 1) store song times (possibly after playing)
2) seeking 2) possibly, crossfading
3) set flags (such as BAD MP3) 3) resample in software for sound cards that support a limited range of
sampling rate.
possibly: 4) Password protection
---------
reference songs by an id #
spawn a seperate process for db updates, that pipes updates through a socket
to the main process
Music Player Daemon (MPD) - UPGRADING Music Player Daemon (MPD) - UPGRADING
Upgrading to 0.8.0 Upgrading to 0.9.x
------------------ ------------------
If you have flacs, then to have them added to your list of available music, The "stop_on_error" config parameter was removed, so be sure to remove this
parameter from your config file.
Upgrading to 0.8.x
------------------
If you have FLACs, then to have them added to your list of available music,
just use "update". just use "update".
Upgrading from 0.5.x to 0.6.x Upgrading from 0.5.x to 0.6.x
----------------------------- -----------------------------
If you have not compiled MPD with "make ogg", then nothing is needed. If you have not compiled MPD with "make ogg", then nothing is needed.
If you compiled with "make ogg", just use "update" (availabe via the phpMp If you compiled with "make ogg", just use "update" (available via the phpMp
interface) to add your ogg's to MPD's list of available music. interface) to add your OGGs to MPD's list of available music.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
AC_INIT(main.c) AC_INIT(src/main.c)
AM_INIT_AUTOMAKE(mpd, 0.8.7) AM_INIT_AUTOMAKE(mpd, 0.9.0)
AC_PROG_CC AC_PROG_CC
AC_PROG_INSTALL AC_PROG_INSTALL
...@@ -26,18 +26,83 @@ AC_ARG_ENABLE(mpd_mad,[ --enable-mpd-mad use mpd libmad],use_mpd_mad=yes,) ...@@ -26,18 +26,83 @@ AC_ARG_ENABLE(mpd_mad,[ --enable-mpd-mad use mpd libmad],use_mpd_mad=yes,)
AC_ARG_ENABLE(id3,[ --disable-id3 disable id3 support],,enable_id3=yes) AC_ARG_ENABLE(id3,[ --disable-id3 disable id3 support],,enable_id3=yes)
AC_ARG_ENABLE(mpd_id3tag,[ --enable-mpd-id3tag use mpd libid3tag],use_mpd_id3tag=yes,) AC_ARG_ENABLE(mpd_id3tag,[ --enable-mpd-id3tag use mpd libid3tag],use_mpd_id3tag=yes,)
AC_ARG_WITH(id3tag,[ --with-id3tag=PFX Prefix where libid3tag is installed (optional)], id3tag_prefix="$withval", id3tag_prefix="")
AC_ARG_WITH(id3tag-libraries,[ --with-id3tag-libraries=DIR Directory where libid3tag library is installed (optional)], id3tag_libraries="$withval", id3tag_libraries="")
AC_ARG_WITH(id3tag-includes,[ --with-id3tag-includes=DIR Directory where libid3tag header files are installed (optional)], id3tag_includes="$withval", id3tag_includes="")
AC_ARG_WITH(mad,[ --with-mad=PFX Prefix where libmad is installed (optional)], mad_prefix="$withval", mad_prefix="")
AC_ARG_WITH(mad-libraries,[ --with-mad-libraries=DIR Directory where libmad library is installed (optional)], mad_libraries="$withval", mad_libraries="")
AC_ARG_WITH(mad-includes,[ --with-mad-includes=DIR Directory where mad header files are installed (optional)], mad_includes="$withval", mad_includes="")
AC_CHECK_LIB(socket,socket,MPD_LIBS="$MPD_LIBS -lsocket",)
AC_CHECK_LIB(nsl,gethostbyname,MPD_LIBS="$MPD_LIBS -lnsl",)
AC_MSG_CHECKING(for ipv6)
AC_EGREP_CPP([AP_maGiC_VALUE],
[
#include <sys/types.h>
#include <sys/socket.h>
#include <netdb.h>
#ifdef PF_INET6
#ifdef AF_INET6
AP_maGiC_VALUE
#endif
#endif
],
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_IPV6"
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no])
)
XIPH_PATH_AO(MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS",AC_MSG_ERROR(Must have libao installed!!!)) XIPH_PATH_AO(MPD_LIBS="$MPD_LIBS $AO_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AO_CFLAGS",AC_MSG_ERROR(Must have libao installed!!!))
AC_CHECK_HEADER(sys/soundcard.h,,[MPD_CFLAGS="$MPD_CFLAGS -DNO_OSS_MIXER";AC_MSG_WARN(Soundcard headers not found -- disabling mixer)]) AC_CHECK_HEADER(sys/soundcard.h,,[MPD_CFLAGS="$MPD_CFLAGS -DNO_OSS_MIXER";AC_MSG_WARN(Soundcard headers not found -- disabling mixer)])
AC_MSG_CHECKING(for alsa)
AC_EGREP_CPP([AP_maGiC_VALUE],
[
#include <alsa/asoundlib.h>
#if defined(SND_LIB_MAJOR) && defined(SND_LIB_MINOR)
#if SND_LIB_MAJOR>0 || (SND_LIB_MAJOR==0 && SND_LIB_MINOR>=6)
AP_maGiC_VALUE
#endif
#endif
],
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_ALSA"
MPD_LIBS="$MPD_LIBS -lasound"
AC_MSG_RESULT([yes]),
AC_MSG_RESULT([no])
)
ID3_SUBDIR="" ID3_SUBDIR=""
if test x$enable_id3 = xyes; then if test x$enable_id3 = xyes; then
if test x$use_mpd_id3tag = xyes; then if test x$use_mpd_id3tag = xyes; then
ID3_SUBDIR="libid3tag" ID3_SUBDIR="libid3tag"
else else
if test "x$id3tag_libraries" != "x" ; then
ID3TAG_LIBS="-L$id3tag_libraries"
elif test "x$id3tag_prefix" != "x" ; then
ID3TAG_LIBS="-L$id3tag_prefix/lib"
elif test "x$prefix" != "xNONE"; then
ID3TAG_LIBS="-L$libdir"
fi
ID3TAG_LIBS="$ID3TAG_LIBS -lid3tag -lz"
if test "x$id3tag_includes" != "x" ; then
ID3TAG_CFLAGS="-I$id3tag_includes"
elif test "x$id3tag_prefix" != "x" ; then
ID3TAG_CFLAGS="-I$id3tag_prefix/lib"
elif test "x$prefix" != "xNONE"; then
ID3TAG_CFLAGS="-I$libdir"
fi
ID3TAG_CFLAGS="$ID3TAG_CFLAGS"
oldcflags=$CFLAGS oldcflags=$CFLAGS
CFLAGS="$CFLAGS -lz" CFLAGS="$CFLAGS $ID3TAG_CFLAGS $ID3TAG_LIBS"
AC_CHECK_LIB(id3tag,id3_file_open,[ID3_LIB="-lid3tag -lz"; AC_CHECK_LIB(id3tag,id3_file_open,[ID3_LIB="$ID3TAG_LIBS";
MPD_CFLAGS="$MPD_CFLAGS $ID3TAG_CFLAGS";
use_libid3tag=yes], use_libid3tag=yes],
[use_libid3tag=no;use_mpd_id3tag=yes]) [use_libid3tag=no;use_mpd_id3tag=yes])
CFLAGS=$oldcflags CFLAGS=$oldcflags
...@@ -46,7 +111,7 @@ if test x$enable_id3 = xyes; then ...@@ -46,7 +111,7 @@ if test x$enable_id3 = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_ID3TAG" MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_ID3TAG"
ID3_LIB="libid3tag/libid3tag.la" ID3_LIB="libid3tag/libid3tag.la"
ID3_SUBDIR="libid3tag" ID3_SUBDIR="libid3tag"
AC_CONFIG_SUBDIRS(libid3tag) AC_CONFIG_SUBDIRS(src/libid3tag)
fi fi
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_ID3TAG" MPD_CFLAGS="$MPD_CFLAGS -DHAVE_ID3TAG"
fi fi
...@@ -57,24 +122,94 @@ if test x$enable_mp3 = xyes; then ...@@ -57,24 +122,94 @@ if test x$enable_mp3 = xyes; then
if test x$use_mpd_mad = xyes; then if test x$use_mpd_mad = xyes; then
MAD_SUBDIR="libmad" MAD_SUBDIR="libmad"
else else
AC_CHECK_LIB(mad,mad_stream_init,[MAD_LIB=-lmad;use_libmad=yes], if test "x$mad_libraries" != "x" ; then
MAD_LIBS="-L$mad_libraries"
elif test "x$mad_prefix" != "x" ; then
MAD_LIBS="-L$mad_prefix/lib"
elif test "x$prefix" != "xNONE"; then
MAD_LIBS="-L$libdir"
fi
MAD_LIBS="$MAD_LIBS -lmad"
if test "x$mad_includes" != "x" ; then
MAD_CFLAGS="-I$mad_includes"
elif test "x$mad_prefix" != "x" ; then
MAD_CFLAGS="-I$mad_prefix/lib"
elif test "x$prefix" != "xNONE"; then
MAD_CFLAGS="-I$libdir"
fi
AC_CHECK_LIB(mad,mad_stream_init,[MAD_LIB="$MAD_LIBS";
MPD_CFLAGS="$MPD_CFLAGS $MAD_CFLAGS";use_libmad=yes],
[use_libmad=no;use_mpd_mad=yes]) [use_libmad=no;use_mpd_mad=yes])
fi fi
if test x$use_mpd_mad = xyes; then if test x$use_mpd_mad = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_MAD" MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_MAD"
MAD_LIB="libmad/libmad.la" MAD_LIB="libmad/libmad.la"
MAD_SUBDIR="libmad" MAD_SUBDIR="libmad"
AC_CONFIG_SUBDIRS(libmad) AC_CONFIG_SUBDIRS(src/libmad)
fi fi
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_MAD" MPD_CFLAGS="$MPD_CFLAGS -DHAVE_MAD"
fi fi
if test x$enable_ogg = xyes; then if test x$enable_ogg = xyes; then
XIPH_PATH_OGG(MPD_LIBS="$MPD_LIBS $OGG_LIBS" MPD_CFLAGS="$MPD_CFLAGS $OGG_CFLAGS" enable_vorbistest=no,enable_ogg=no) XIPH_PATH_OGG(MPD_LIBS="$MPD_LIBS $OGG_LIBS" MPD_CFLAGS="$MPD_CFLAGS $OGG_CFLAGS",enable_ogg=no)
fi fi
if test x$enable_ogg = xyes; then if test x$enable_ogg = xyes; then
XIPH_PATH_VORBIS(MPD_LIBS="$MPD_LIBS $VORBIS_LIBS $VORBISFILE_LIBS" MPD_CFLAGS="$MPD_CFLAGS $VORBIS_CFLAGS $VORBISFILE_CFLAGS",enable_ogg=no) enable_vorbistest=no
XIPH_PATH_VORBIS(,enable_ogg=no)
if test x$enable_ogg = xyes; then
dnl
dnl Vorbis Test
dnl vorbistest in XIPH_PATH_OGG is broken on my debian system
dnl so here i used my own hacked up version till i get vorbis-dev gets
dnl upgraded in debian (hopefully when 1.0.1 comes out)
dnl
AC_MSG_CHECKING(that Vorbis is usable)
ac_save_CFLAGS="$CFLAGS"
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $VORBIS_CFLAGS $OGG_CFLAGS"
LIBS="$LIBS $VORBIS_LIBS $VORBISENC_LIBS $OGG_LIBS"
AC_TRY_RUN([
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/codec.h>
#include <vorbis/vorbisenc.h>
int main ()
{
vorbis_block vb;
vorbis_dsp_state vd;
vorbis_info vi;
vorbis_info_init (&vi);
vorbis_encode_init (&vi, 2, 44100, -1, 128, -1);
/*vorbis_analysis_init (&vd, &vi);
vorbis_block_init (&vd, &vb);*/
/* this function was added in 1.0rc3, so this is what we're testing for */
/*vorbis_bitrate_addblock (&vb);*/
return 0;
}
], AC_MSG_RESULT(yes), AC_MSG_RESULT(no) enable_ogg=no,[echo $ac_n "cross compiling; assumed OK... $ac_c"])
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
fi
dnl
dnl End of Vorbis Test
dnl
if test x$enable_ogg = xyes; then
MPD_LIBS="$MPD_LIBS $VORBIS_LIBS $VORBISFILE_LIBS"
MPD_CFLAGS="$MPD_CFLAGS $VORBIS_CFLAGS $VORBISFILE_CFLAGS"
fi
fi fi
if test x$enable_ogg = xyes; then if test x$enable_ogg = xyes; then
...@@ -107,4 +242,4 @@ if test x$enable_flac = xyes; then ...@@ -107,4 +242,4 @@ if test x$enable_flac = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_FLAC" MPD_CFLAGS="$MPD_CFLAGS -DHAVE_FLAC"
fi fi
AC_OUTPUT(Makefile) AC_OUTPUT(debian/Makefile doc/Makefile src/Makefile Makefile )
EXTRA_DIST = changelog compat control copyright dirs docs rules
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
ID3_LIB = @ID3_LIB@
ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
MPD_LIBS = @MPD_LIBS@
OBJDUMP = @OBJDUMP@
OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
VORBISFILE_LIBS = @VORBISFILE_LIBS@
VORBIS_CFLAGS = @VORBIS_CFLAGS@
VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
EXTRA_DIST = changelog compat control copyright dirs docs rules
subdir = debian
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
DIST_SOURCES =
DIST_COMMON = Makefile.am Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign debian/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
tags: TAGS
TAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile
installdirs:
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am:
install-exec-am:
install-info: install-info-am
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
uninstall-am: uninstall-info-am
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
distclean distclean-generic distclean-libtool distdir dvi \
dvi-am info info-am install install-am install-data \
install-data-am install-exec install-exec-am install-info \
install-info-am install-man install-strip installcheck \
installcheck-am installdirs maintainer-clean \
maintainer-clean-generic mostlyclean mostlyclean-generic \
mostlyclean-libtool uninstall uninstall-am uninstall-info-am
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
mpd (0.9.0-1) unstable; urgency=low
* Update to 0.9.0
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 29 Sep 2003 19:39:00 -0400
mpd (0.8.7-1) unstable; urgency=low
* Update to 0.8.7
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 03 Sep 2003 22:39:00 -0400
mpd (0.8.6-1) unstable; urgency=low
* Update to 0.8.6
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 25 Aug 2003 20:35:00 -0400
mpd (0.8.5-1) unstable; urgency=low
* Update to 0.8.5
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 17 Aug 2003 22:50:00 -0400
mpd (0.8.4-1) unstable; urgency=low
* Update to 0.8.4
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 12 Aug 2003 19:35:00 -0400
mpd (0.8.3-1) unstable; urgency=low
* Update to 0.8.3
-- Warren Dukes <shank@mercury.chem.pitt.edu> Tue, 12 Aug 2003 19:35:00 -0400
mpd (0.8.2-1) unstable; urgency=low
* Initial Release.
-- Warren Dukes <shank@mercury.chem.pitt.edu> Fri, 25 Jul 2003 10:28:30 -0400
Source: mpd
Section: sound
Priority: optional
Maintainer: Warren Dukes <shank@mercury.chem.pitt.edu>
Build-Depends: debhelper (>> 4.0.0), libao-dev (>=0.8.3-1), libogg-dev, libvorbis-dev, libflac-dev (>=1.1.0-4), libmad0-dev, libid3tag0-dev
Standards-Version: 3.5.8
Package: mpd
Architecture: any
Depends: ${shlibs:Depends}
Description: Music Player Daemon (MPD)
MPD is a server that allows remote access for playing
music (MP3, Ogg Vorbis, and Flac) and managing playlists. The design focus is
on integrating a computer into a stereo system that provides control for music
playback over a local network. Currently, it includes a Web interface, phpMp;
a command line tool, mpc; and a dock app, WMmp. The goals are to be easy to
install and use, to have minimal resource requirements, and to be stable and
flexible.
This package was debianized by Warren Dukes <shank@mercury.chem.pitt.edu> on
Fri, 25 Jul 2003 10:28:30 -0400.
It was downloaded from http://musicpd.sf.net
Upstream Author: Warren Dukes <shank@mercury.chem.pitt.edu>
This software is copyright (c) 2003 by Warren Dukes
You are free to distribute this software under the terms of
the GNU General Public License.
On Debian systems, the complete text of the GNU General Public
License can be found in the file `/usr/share/common-licenses/GPL'.
usr/bin
usr/share/man/man1
#!/usr/bin/make -f
# Sample debian/rules that uses debhelper.
# GNU copyright 1997 to 1999 by Joey Hess.
# Uncomment this to turn on verbose mode.
#export DH_VERBOSE=1
# These are used for cross-compiling and for saving the configure script
# from having to guess our platform (since we know it already)
DEB_HOST_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
DEB_BUILD_GNU_TYPE ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
CFLAGS = -Wall -g
ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
CFLAGS += -O0
else
CFLAGS += -O2
endif
ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
INSTALL_PROGRAM += -s
endif
config.status: configure
dh_testdir
# Add here commands to configure the package.
./configure --host=$(DEB_HOST_GNU_TYPE) --build=$(DEB_BUILD_GNU_TYPE) --prefix=/usr --mandir=\$${prefix}/share/man --infodir=\$${prefix}/share/info
build: build-stamp
build-stamp: config.status
dh_testdir
# Add here commands to compile the package.
$(MAKE)
#/usr/bin/docbook-to-man debian/mpd.sgml > mpd.1
touch build-stamp
clean:
dh_testdir
dh_testroot
rm -f build-stamp
# Add here commands to clean up after the build process.
-$(MAKE) distclean
ifneq "$(wildcard /usr/share/misc/config.sub)" ""
cp -f /usr/share/misc/config.sub config.sub
endif
ifneq "$(wildcard /usr/share/misc/config.guess)" ""
cp -f /usr/share/misc/config.guess config.guess
endif
dh_clean
install: build
dh_testdir
dh_testroot
dh_clean -k
dh_installdirs
# Add here commands to install the package into debian/mpd.
$(MAKE) install DESTDIR=$(CURDIR)/debian/mpd
# Build architecture-independent files here.
binary-indep: build install
# We have nothing to do by default.
# Build architecture-dependent files here.
binary-arch: build install
dh_testdir
dh_testroot
dh_installchangelogs ChangeLog
dh_installdocs
dh_installexamples doc/mpdconf.example
# dh_install
# dh_installmenu
# dh_installdebconf
# dh_installlogrotate
# dh_installemacsen
# dh_installpam
# dh_installmime
# dh_installinit
# dh_installcron
# dh_installinfo
dh_installman
# dh_link
dh_strip
dh_compress
dh_fixperms
# dh_perl
# dh_python
# dh_makeshlibs
dh_installdeb
dh_shlibdeps
dh_gencontrol
dh_md5sums
dh_builddeb
binary: binary-indep binary-arch
.PHONY: build clean binary-indep binary-arch binary install
...@@ -14,7 +14,7 @@ command <type arg1> <type arg2> ... ...@@ -14,7 +14,7 @@ command <type arg1> <type arg2> ...
Command Completion: Command Completion:
------------------- -------------------
A command returns "OK\n" on completeion or "ACK some error\n" on failure. A command returns "OK\n" on completion or "ACK some error\n" on failure.
These denote the end of command execution. These denote the end of command execution.
Commands: Commands:
...@@ -31,7 +31,7 @@ clearerror ...@@ -31,7 +31,7 @@ clearerror
(this is also accomplished by any command that starts playback) (this is also accomplished by any command that starts playback)
close close
close the connection with the mpd close the connection with the MPD
delete <int song> delete <int song>
delete _song_ from playlist delete _song_ from playlist
...@@ -42,12 +42,12 @@ find <string type> <string what> ...@@ -42,12 +42,12 @@ find <string type> <string what>
_what_ is what to find _what_ is what to find
kill kill
kill mpd kill MPD
list <string type> <string arg1> list <string type> <string arg1>
list all tags of _type_ list all tags of _type_
_type_ should be "album" or "artist" _type_ should be "album" or "artist"
_arg1_ is an optional paramter when type is album, this specifies _arg1_ is an optional parameter when type is album, this specifies
to list albums by a artist, where artist is specified with to list albums by a artist, where artist is specified with
arg1 arg1
...@@ -66,6 +66,9 @@ ls <string directory> ...@@ -66,6 +66,9 @@ ls <string directory>
lsinfo <string directory> lsinfo <string directory>
list contents of _directory_, from the db. _directory_ is optional list contents of _directory_, from the db. _directory_ is optional
move <int from> <int to>
move song at _from_ to _to_ in the playlist
next next
plays next song in playlist plays next song in playlist
...@@ -73,7 +76,7 @@ pause ...@@ -73,7 +76,7 @@ pause
pause/resume playing pause/resume playing
play <int song> play <int song>
begin playling playlist at song number _song_, _song_ is optiional begin playing playlist at song number _song_, _song_ is optional
playlist playlist
displays the current playlist displays the current playlist
...@@ -85,19 +88,23 @@ playlistinfo ...@@ -85,19 +88,23 @@ playlistinfo
previous previous
plays previous song in playlist plays previous song in playlist
repeat <int state>
set repeat state to _state_, _state_ should be 0 or 1
rm <string name> rm <string name>
removes the playlist <name>.m3u from the playlist directory removes the playlist <name>.m3u from the playlist directory
save <string name> save <string name>
saves the current playlist to _name_.m3u in the playlist directory saves the current playlist to _name_.m3u in the playlist directory
repeat <int state>
set repeat state to _state_, _state_ should be 0 or 1
search <string type> <string what> search <string type> <string what>
same as "find" but searches for any song that contain _what_ same as "find" but searches for any song that contain _what_
search is not case sensitive search is not case sensitive
seek <int song> <int time>
seeks to the position _time_ (in seconds) of entry _song_ in the
playlist
shuffle shuffle
shuffles the current playlist shuffles the current playlist
...@@ -107,15 +114,16 @@ stats ...@@ -107,15 +114,16 @@ stats
albums: number of albums albums: number of albums
songs: number of songs songs: number of songs
uptime: daemon uptime in seconds uptime: daemon uptime in seconds
db_update: last db update in unix time db_update: last db update in UNIX time
playtime: time length of music played playtime: time length of music played
songs_played: total number of songs played songs_played: total number of songs played
status status
reports current status of player, and volume level. reports current status of player, and volume level.
volume: (0-100). volume: (0-100).
repat: (0 or 1) repeat: (0 or 1)
playlist: (31-bit unsigned integer, the playlist version number) playlist: (31-bit unsigned integer, the playlist version number)
playlistlength: (integer, the length of the playlist)
state: ("play", "stop", or "pause") state: ("play", "stop", or "pause")
song: (current song playing/paused, playlist song number) song: (current song playing/paused, playlist song number)
time: <int elapsed>:<time total> (of current playing/paused song) time: <int elapsed>:<time total> (of current playing/paused song)
...@@ -124,6 +132,9 @@ status ...@@ -124,6 +132,9 @@ status
stop stop
stop playing stop playing
swap <int song1> <int song2>
swap positions of _song1_ and _song2_
update update
searches mp3 directory for new music and removes old music from the db searches mp3 directory for new music and removes old music from the db
...@@ -133,7 +144,7 @@ volume <int change> ...@@ -133,7 +144,7 @@ volume <int change>
COMMAND LIST COMMAND LIST
------------ ------------
To faciliate faster adding of files, etc, you can pass a list of commands all To facilitate faster adding of files, etc, you can pass a list of commands all
at once using a command list. The command list beings with: at once using a command list. The command list beings with:
command_list_begin command_list_begin
......
man_MANS = mpd.1
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = COMMANDS
EXTRA_DIST = mpdconf.example $(man_MANS) $(doc_DATA)
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
ID3_LIB = @ID3_LIB@
ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
MPD_LIBS = @MPD_LIBS@
OBJDUMP = @OBJDUMP@
OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
VORBISFILE_LIBS = @VORBISFILE_LIBS@
VORBIS_CFLAGS = @VORBIS_CFLAGS@
VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
man_MANS = mpd.1
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = COMMANDS
EXTRA_DIST = mpdconf.example $(man_MANS) $(doc_DATA)
subdir = doc
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
DIST_SOURCES =
NROFF = nroff
MANS = $(man_MANS)
DATA = $(doc_DATA)
DIST_COMMON = Makefile.am Makefile.in
all: all-am
.SUFFIXES:
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign doc/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
man1dir = $(mandir)/man1
install-man1: $(man1_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(man1dir)
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
if test -f $(srcdir)/$$i; then file=$(srcdir)/$$i; \
else file=$$i; fi; \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
case "$$ext" in \
1*) ;; \
*) ext='1' ;; \
esac; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " $(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man1dir)/$$inst; \
done
uninstall-man1:
@$(NORMAL_UNINSTALL)
@list='$(man1_MANS) $(dist_man1_MANS) $(nodist_man1_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.1*) list="$$list $$i" ;; \
esac; \
done; \
for i in $$list; do \
ext=`echo $$i | sed -e 's/^.*\\.//'`; \
inst=`echo $$i | sed -e 's/\\.[0-9a-z]*$$//'`; \
inst=`echo $$inst | sed -e 's/^.*\///'`; \
inst=`echo $$inst | sed '$(transform)'`.$$ext; \
echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
rm -f $(DESTDIR)$(man1dir)/$$inst; \
done
docDATA_INSTALL = $(INSTALL_DATA)
install-docDATA: $(doc_DATA)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(docdir)
@list='$(doc_DATA)'; for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " $(docDATA_INSTALL) $$d$$p $(DESTDIR)$(docdir)/$$f"; \
$(docDATA_INSTALL) $$d$$p $(DESTDIR)$(docdir)/$$f; \
done
uninstall-docDATA:
@$(NORMAL_UNINSTALL)
@list='$(doc_DATA)'; for p in $$list; do \
f="`echo $$p | sed -e 's|^.*/||'`"; \
echo " rm -f $(DESTDIR)$(docdir)/$$f"; \
rm -f $(DESTDIR)$(docdir)/$$f; \
done
tags: TAGS
TAGS:
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-am
all-am: Makefile $(MANS) $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(man1dir) $(DESTDIR)$(docdir)
install: install-am
install-exec: install-exec-am
install-data: install-data-am
uninstall: uninstall-am
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-am
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-am
distclean-am: clean-am distclean-generic distclean-libtool
dvi: dvi-am
dvi-am:
info: info-am
info-am:
install-data-am: install-docDATA install-man
install-exec-am:
install-info: install-info-am
install-man: install-man1
installcheck-am:
maintainer-clean: maintainer-clean-am
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-am
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
uninstall-am: uninstall-docDATA uninstall-info-am uninstall-man
uninstall-man: uninstall-man1
.PHONY: all all-am check check-am clean clean-generic clean-libtool \
distclean distclean-generic distclean-libtool distdir dvi \
dvi-am info info-am install install-am install-data \
install-data-am install-docDATA install-exec install-exec-am \
install-info install-info-am install-man install-man1 \
install-strip installcheck installcheck-am installdirs \
maintainer-clean maintainer-clean-generic mostlyclean \
mostlyclean-generic mostlyclean-libtool uninstall uninstall-am \
uninstall-docDATA uninstall-info-am uninstall-man \
uninstall-man1
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
.TH "Music Player Daemon" 1
.SH NAME
MPD \- A daemon for playing music (mp3, ogg vorbis, and flac)
.SH SYNOPSIS
.B mpd
.RI [ options ]
.RI [ CONF_FILE ]
.br
.B mpd
.RI [ options ]
.I PORT MUSIC_DIR PLAYLIST_DIR LOG_FILE ERROR_FILE
.br
.SH DESCRIPTION
MPD is a daemon for playing music (mp3, ogg vorbis, and flac). Music is played
through the server's audio device. The daemon stores info about all available
music, and this info can be easily searched and retrieved. Player control, info
retrieval, and playlist management can all be managed remotely.
MPD searches for a config file in ~/.mpdconf then /etc/mpd.conf or uses
CONF_FILE. Instead of using a config file, the minimal configuration paramters
can be specified on the command line: PORT, MUSIC_DIR, PLAYLIST_DIR, LOG_FILE,
and ERROR_FILE.
Read more about MPD on http://www.musicpd.org
.SH OPTIONS
.TP
.B --create-db
(Re)Crete the db file for mpd.
.TP
.BI --help
Output a brief help message.
.br
.TP
.BI --no-daemon
Don't detach from console or redirect output to log files.
.TP
.BI --verbose
Output verbose amounts of information to the logs
.TP
.BI --version
Print version information.
.SH PARAMETERS
Below are a list of parameters that can be specified in the config file. Each line in the config file should be of the form:
.br
parameter "value"
.TP
.B port <port>
This specifies the port that MPD listens on. This parameter is required. This is typically 2100.
.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.
.TP
.B playlist_directory <directory>
This specifies the directory where saved playlists are stored. This parameter is required. The directory path should be an absolute path.
.TP
.B log_file <file>
This specifies where the log file should be located. This parameter is required. The file path should be an absolute path.
.TP
.B error_file <file>
This specifies where the error file should be located. This parameter is required. The file path should be an absolute path.
.TP
.B log_level <default, secure, or verbose>
This specifies how verbose logs are. "default" is minimal logging, "secure" reports from what address a connection is opened, and when it is closed, and "verbose" records excessive amounts of information for debugging purposes. The default is "default".
.TP
.B db_file <file>
This specifies where the db file will be stored. The file path should be an
absolute path. The default is ".mpddb" in the playlist directory.
.TP
.B state_file <file>
This specifies if a state file is used and where it is located. The file path should be an absolute path. The state of mpd will be saved to this file when mpd is terminated by a TERM signal or by the "kill" command.
.TP
.B user <user>
This specifies the user that mpd will run as, if set.
.TP
.B connection_timeout <seconds>
If a client does not send any new data in this time period, the connection is closed. The default is 60 seconds.
.TP
.B max_connections <int>
This specifies the maximum number of clients that can be connected to MPD. The default is 5 connections.
.TP
.B mixer_device <mixer dev>
This specifies which mixer to use. The default for oss is /dev/mixer;
the default for alsa is "hw:0".
.TP
.B mixer_type <oss or alsa>
This specifies which mixer to use. The default is oss.
.TP
.B max_playlist_length <int>
This specifies the maximum number of songs that can be in the playlist. The default is 4096 songs.
.TP
.B buffer_before play <0-100%>
This specifies the amount of buffer that will be filled before a song begins playing. The default is 25%.
.TP
.B stop_on_error <yes or no>
This specifies whether playback should stop or goto the next song when an error occurs. The default is no.
.TP
.B max_command_list_size <size in KB>
This specifies the maximum size a command list can be (in kilobytes). The default is 2048 kilobytes.
.TP
.B max_output_buffer_size <size in KB>
This specifies the maximum size of the output buffer to a client (in kilobytes).
The default is 2048 kilobytes.
.TP
.B ao_driver <ao plug-in>
This specifies the ao plug-in to use for audio output. Typical values for
Linux include "oss" and "alsa09". The default value is "default".
.TP
.B ao_driver_options <ao plug-in options>
This specifies the options to use for the selected ao_driver. For oss, the
only option available is "dsp". For alsa09, the available options are:
"dev", "buf_size", and "periods". Options are assigned using "=" and ";" is
used to separate options. An example for oss: "dsp=/dev/dsp". An example for
alsa09: "dev=hw:0,0;buf_size=4096". The default value is "".
.TP
.B save_absolute_paths_in_playlists <yes or no>
This specifies whether relative or absolute paths for song filenames are
used when saving playlists. The default value is "no".
.TP
.B bind_to_address <ip address or hostname or any>
This specifies which address MPD binds to and listens on. The default is "any",
which binds to all available addresses.
.SH EXAMPLES
.TP
Below is an example config file.
.br
.br
# required
.br
port "2100"
.br
music_directory "/home/shank/mp3"
.br
playlist_directory "/home/shank/playlists"
.br
log_file "/home/shank/mpd.log"
.br
error_file "/home/shank/mpd.error"
.br
.br
# optional
.br
mixer_type "oss"
.br
mixer_device "/dev/mixer"
.br
#mixer_type "alsa"
.br
#mixer_device "default"
.br
#ao_driver "oss"
.br
#ao_driver_options "dsp=/dev/dsp"
.br
max_playlist_length "4096"
.br
buffer_before_play "25%"
.br
#db_file "/home/shank/playlists/.mpddb"
.br
#state_file "/home/shank/playlists/.mpdstate"
.br
#user "shank"
.br
connection_timeout "60"
.br
max_connections "5"
.br
max_command_list_size "2048"
.br
max_output_buffer_size "2048"
.br
save_absolute_paths_in_playlists "no"
.br
# log_level can be "default", "secure", "verbose"
.br
log_level "default"
.br
# if bind_to_address is "any", MPD binds all addresses
.br
bind_to_address "any"
.SH SEE ALSO
mpc(1)
...@@ -6,16 +6,23 @@ log_file "/home/shank/mpd.log" ...@@ -6,16 +6,23 @@ log_file "/home/shank/mpd.log"
error_file "/home/shank/mpd.error" error_file "/home/shank/mpd.error"
# optional # optional
connection_timeout "60" mixer_type "oss"
mixer_device "/dev/mixer" mixer_device "/dev/mixer"
max_connections "5" #mixer_type "alsa"
#mixer_device "default"
#ao_driver "oss"
#ao_driver_options "dsp=/dev/dsp"
max_playlist_length "4096" max_playlist_length "4096"
buffer_before_play "25%" buffer_before_play "25%"
stop_on_error "yes" #db_file "/home/shank/playlists/.mpddb"
#state_file "/home/shank/playlists/.mpdstate"
#user "shank"
connection_timeout "60"
max_connections "5"
max_command_list_size "2048" max_command_list_size "2048"
max_output_buffer_size "2048" max_output_buffer_size "2048"
ao_driver "oss"
ao_driver_options "dsp=/dev/dsp"
save_absolute_paths_in_playlists "no" save_absolute_paths_in_playlists "no"
# when bind_to_address is set to "any", mpd binds all availabe addresses # log_level can be "default", "secure", "verbose"
log_level "default"
# when bind_to_address is set to "any", MPD binds all available addresses
bind_to_address "any" bind_to_address "any"
/* the Music Player Daemon (MPD)
* (c)2003 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
*/
#ifdef HAVE_FLAC
#include "flac_decode.h"
#include "player.h"
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "buffer.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <ao/ao.h>
#include <FLAC/file_decoder.h>
#include <FLAC/metadata.h>
#define INPUT_BUFFER_SIZE 80
#define CHECK_INPUT_FREQ 300 /* about once very 0.1 seconds */
#define TIME_TELL_INTERVAL 0.2
#ifndef FALSE
#define FALSE (0)
#endif
#ifndef TRUE
#define TRUE (!FALSE)
#endif
typedef struct {
unsigned char chunk[CHUNK_SIZE];
int chunk_length;
float time;
Buffer * cb;
ao_sample_format * format;
} FlacData;
int flac_decode_pid = 0;
int flac_decode_done = 0;
ao_device * flac_device = NULL;
/* this code is based on flac123, from flac-tools */
void flacPlayfile(const char * file, Buffer * cb, ao_sample_format * format);
void flacError(const FLAC__FileDecoder *, FLAC__StreamDecoderErrorStatus, void *);
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(const char *file, Buffer * cb, ao_sample_format * format)
{
FLAC__FileDecoder * flacDec;
FlacData data;
data.chunk_length = 0;
data.time = 0;
data.cb = cb;
data.format = format;
flacDec = FLAC__file_decoder_new();
FLAC__file_decoder_set_md5_checking(flacDec,TRUE);
FLAC__file_decoder_set_filename(flacDec,file);
FLAC__file_decoder_set_write_callback(flacDec,flacWrite);
FLAC__file_decoder_set_metadata_callback(flacDec,flacMetadata);
FLAC__file_decoder_set_error_callback(flacDec,flacError);
FLAC__file_decoder_set_client_data(flacDec, (void *)&data);
FLAC__file_decoder_init(flacDec);
FLAC__file_decoder_process_until_end_of_file(flacDec);
FLAC__file_decoder_finish(flacDec);
FLAC__file_decoder_delete(flacDec);
}
void flacError(const FLAC__FileDecoder *dec, FLAC__StreamDecoderErrorStatus status, void *data) {
}
void flacMetadata(const FLAC__FileDecoder *dec, const FLAC__StreamMetadata *meta, void *data) {
}
void flacSendChunk(FlacData * data) {
while(data->cb->begin==data->cb->end && data->cb->wrap)
usleep(100);
memcpy(data->cb->chunks[data->cb->end],data->chunk,CHUNK_SIZE);
data->cb->times[data->cb->end] = data->time;
data->cb->end++;
if(data->cb->end>=BUFFERED_CHUNKS) {
data->cb->end = 0;
data->cb->wrap = 1;
}
}
FLAC__StreamDecoderWriteStatus flacWrite(const FLAC__FileDecoder *dec, const FLAC__Frame *frame, const FLAC__int32 * const buf[], void * vdata) {
FlacData * data = (FlacData *)vdata;
uint_32 dataSize = frame->header.blocksize * frame->header.channels
* (data->format->bits / 8);
uint_32 samples = frame->header.blocksize;
uint_16 ldb[samples*frame->header.channels];
int c_samp, c_chan, d_samp;
unsigned char * ldbuc = (unsigned char *)ldb;
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++) {
ldb[d_samp] = buf[c_chan][c_samp];
}
}
data->time+=((float)samples)/frame->header.sample_rate;
while(dataSize>0) {
if(data->chunk_length>=CHUNK_SIZE) {
flacSendChunk(data);
data->chunk_length = 0;
}
data->chunk[data->chunk_length++] = *(ldbuc++);
dataSize--;
}
return FLAC__STREAM_DECODER_WRITE_STATUS_CONTINUE;
}
int flac_getAoDataAndTime(char * file, ao_sample_format * format, float * time) {
FLAC__Metadata_SimpleIterator * it;
FLAC__StreamMetadata * block = NULL;
int found = 0;
int ret = -1;
it = FLAC__metadata_simple_iterator_new();
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->rate = block->data.stream_info.sample_rate;
format->channels = block->data.stream_info.channels;
format->byte_format = AO_FMT_LITTLE;
*time = ((float)block->data.stream_info.total_samples)/format->rate;
ret = 0;
}
if(block) FLAC__metadata_object_delete(block);
FLAC__metadata_simple_iterator_delete(it);
return ret;
}
void flac_decode_parentSigHandler(int sig) {
if(sig==SIGCHLD) {
if(flac_decode_pid==wait3(NULL,WNOHANG,NULL)) {
flac_decode_pid = 0;
flac_decode_done = 1;
}
}
if(sig==SIGTERM) {
int pid = flac_decode_pid;
if(pid>0) kill(pid,SIGTERM);
if(flac_device) ao_close(flac_device);
exit(0);
}
}
/* flac_decode w/ buffering
* this will fork another process
* child process does decoding
* parent process does buffering && playing audio
*/
int flac_decode(char * file, FILE * in, FILE * out) {
Buffer * cb;
ao_sample_format format;
float total_time;
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = flac_decode_parentSigHandler;
sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGTERM,&sa,NULL);
cb = getBuffer();
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
cb->finished = 0;
if(flac_getAoDataAndTime(file,&format,&total_time)<0) {
fprintf(stderr,"%s \"%s\" doesn't seem to be a flac\n",COMMAND_RESPOND_ERROR,file);
return PLAYER_EXIT_ERROR_FILE;
}
fflush(NULL);
flac_decode_pid = fork();
if(flac_decode_pid==0) {
/* CHILD */
fclose(in);
fclose(out);
flacPlayFile(file,cb,&format);
cb->finished = 1;
exit(0);
/* END OF CHILD */
}
else if(flac_decode_pid<0) {
fprintf(stderr,"%s flac_decode Problems fork'ing\n",COMMAND_RESPOND_ERROR);
return PLAYER_EXIT_ERROR_SYSTEM;
}
{
/* PARENT */
float elapsed = 0;
float last_tell = 0;
int pause = 0;
char input[INPUT_BUFFER_SIZE+1];
int playsPerChunk = CHUNK_SIZE/PLAY_SIZE;
int currentPlayChunk = 0;
int quit = 0;
fd_set fds;
struct timeval tv;
int checkInput = 0;
int pid;
tv.tv_sec = 0;
tv.tv_usec = 0;
initAudio();
flac_device = ao_open_live(audio_ao_driver_id,&format,
audio_ao_options);
if(flac_device == NULL) {
audioError();
pid = flac_decode_pid;
if(pid>0) kill(pid,SIGTERM);
return PLAYER_EXIT_ERROR_AUDIO;
}
fprintf(out,"%s\n",PLAYER_START);
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,total_time);
fflush(out);
while(flac_decode_pid>0 && !cb->wrap && cb->end-cb->begin<buffered_before_play && !cb->finished) {
usleep(1000);
}
while(!quit) {
if(pause || checkInput%CHECK_INPUT_FREQ==0) {
FD_ZERO(&fds);
FD_SET(fileno(in),&fds);
fflush(in);
if(select(fileno(in)+1,&fds,NULL,NULL,&tv)) {
myFgets(input,INPUT_BUFFER_SIZE,in);
if(strcasecmp(PLAYER_PAUSE,input)==0) {
fprintf(out,"%s\n",PLAYER_PAUSE_GOT);
fflush(out);
pause = !pause;
}
}
checkInput = 1;
}
checkInput++;
if(pause) usleep(100);
else if(cb->begin!=cb->end || cb->wrap) {
if(currentPlayChunk==0) elapsed = cb->times[cb->begin];
ao_play(flac_device,cb->chunks[cb->begin]+currentPlayChunk*PLAY_SIZE,PLAY_SIZE);
currentPlayChunk++;
if(currentPlayChunk>=playsPerChunk) {
currentPlayChunk=0;
cb->begin++;
if(cb->begin>=BUFFERED_CHUNKS) {
cb->begin = 0;
cb->wrap = 0;
}
}
if(elapsed-last_tell>=TIME_TELL_INTERVAL) {
last_tell = elapsed;
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,total_time);
fflush(out);
}
}
else if(flac_decode_pid<=0 || cb->finished) {
quit = 1;
}
else usleep(200);
}
pid = flac_decode_pid;
if(pid>0) kill(pid,SIGTERM);
ao_close(flac_device);
finishAudio();
/* END OF PARENT */
}
return 0;
}
#endif
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
/* the Music Player Daemon (MPD)
* (c)2002 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 "listen.h"
#include "interface.h"
#include "conf.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <resolv.h>
#include <fcntl.h>
#define MAXHOSTNAME 1024
#define ALLOW_REUSE 1
int listenSocket;
int establish(unsigned short port) {
int allowReuse = ALLOW_REUSE;
int sock;
struct sockaddr_in sockAddr;
struct hostent * he;
memset(&sockAddr, 0, sizeof(struct sockaddr_in));
sockAddr.sin_port = htons(port);
if(strcmp((getConf())[CONF_BIND_TO_ADDRESS],"any")==0) {
sockAddr.sin_family = AF_INET;
sockAddr.sin_addr.s_addr = INADDR_ANY;
}
else {
if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) {
fprintf(stderr,"can't lookup host \"%s\"\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
}
sockAddr.sin_family = he->h_addrtype;
bcopy((char *)he->h_addr,(char *)&sockAddr.sin_addr.s_addr,
he->h_length);
}
if((sock = socket(sockAddr.sin_family,SOCK_STREAM,0)) < 0) {
fprintf(stderr,"socket < 0\n");
return -1;
}
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&allowReuse,sizeof(allowReuse))<0) {
close(sock);
fprintf(stderr,"problems setsockopt'ing\n");
return -1;
}
if(bind(sock,(struct sockaddr *)&sockAddr,sizeof(struct sockaddr_in))<0) {
fprintf(stderr,"unable to bind port %i, maybe mpd is still running?\n",port);
close(sock);
return -1;
}
listen(sock,5);
fcntl(sock,F_SETOWN,(int)getpid());
fcntl(sock,F_SETFL,fcntl(sock,F_GETFL) | O_ASYNC);
return sock;
}
void getConnections(int sock) {
fd_set fdsr;
int fd = 0;
struct timeval tv;
tv.tv_sec = tv.tv_usec = 0;
fflush(NULL);
FD_ZERO(&fdsr);
FD_SET(sock,&fdsr);
if(select(sock+1,&fdsr,NULL,NULL,&tv)==1 &&
((fd = accept(sock,NULL,NULL)) >= 0)) {
openAInterface(fd);
}
else if(fd<0) {
fprintf(stderr,"Problems accept()'ing\n");
}
}
This source diff could not be displayed because it is too large. You can view the blob instead.
/* the Music Player Daemon (MPD)
* (c)2002 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 "interface.h"
#include "command.h"
#include "playlist.h"
#include "directory.h"
#include "tables.h"
#include "player.h"
#include "listen.h"
#include "conf.h"
#include "path.h"
#include "buffer.h"
#include "stats.h"
#include "sig_handlers.h"
#include "audio.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <signal.h>
#include <fcntl.h>
void usage(char * argv[]) {
fprintf(stderr,"usage: %s <port> <mp3/ogg dir> <playlist dir> <log file> <error file>\n",argv[0]);
fprintf(stderr,"or: %s <conf file>\n",argv[0]);
}
int main(int argc, char * argv[]) {
int port;
struct stat st;
FILE * out;
FILE * err;
char * portStr;
char * musicDirArg;
char * playlistDirArg;
char * logFile;
char * errorFile;
initConf();
if(argc==6) {
portStr = argv[1];
musicDirArg = argv[2];
playlistDirArg = argv[3];
logFile = argv[4];
errorFile = argv[5];
}
else if(argc==2) {
char ** conf = readConf(argv[1]);
portStr = conf[CONF_PORT];
musicDirArg = conf[CONF_MUSIC_DIRECTORY];
playlistDirArg = conf[CONF_PLAYLIST_DIRECTORY];
logFile = conf[CONF_LOG_FILE];
errorFile = conf[CONF_ERROR_FILE];
}
else {
usage(argv);
return -1;
}
if((port = atoi(portStr))<0) {
fprintf(stderr,"problem with port number\n");
return -1;
}
if(NULL==(out=fopen(logFile,"a"))) {
fprintf(stderr,"problem opening file \"%s\" for writing\n",logFile);
return -1;
}
if(NULL==(err=fopen(errorFile,"a"))) {
fprintf(stderr,"problem opening file \"%s\" for writing\n",errorFile);
return -1;
}
if(playlistDirArg[0]=='/') {
strcpy(playlistDir,playlistDirArg);
}
else {
getcwd(playlistDir,MAXPATHLEN-strlen(playlistDirArg)-1);
if(playlistDir[strlen(playlistDir)-1]!='/') {
strcat(playlistDir,"/");
}
strcat(playlistDir,playlistDirArg);
}
if(playlistDir[strlen(playlistDir)-1]!='/') {
strcat(playlistDir,"/");
}
if((stat(playlistDir,&st))<0) {
fprintf(stderr,"problem stat'ing \"%s\"\n",playlistDirArg);
return -1;
}
if(!S_ISDIR(st.st_mode)) {
fprintf(stderr,"\"%s\" is not a directory\n",playlistDirArg);
return -1;
}
if(musicDirArg[0]=='/') {
strcpy(musicDir,musicDirArg);
}
else {
getcwd(musicDir,MAXPATHLEN-strlen(musicDirArg)-1);
if(musicDir[strlen(musicDir)-1]!='/') strcat(musicDir,"/");
strcat(musicDir,musicDirArg);
}
if(musicDir[strlen(musicDir)-1]!='/') strcat(musicDir,"/");
if((stat(musicDir,&st))<0) {
fprintf(stderr,"problem stat'ing \"%s\"\n",musicDirArg);
return -1;
}
if(!S_ISDIR(st.st_mode)) {
fprintf(stderr,"\"%s\" is not a directory\n",musicDirArg);
return -1;
}
initTables();
strcpy(directorydb,playlistDir);
strcat(directorydb,"/");
strcat(directorydb,".mpddb");
if(readDirectoryDB()<0) {
initMp3Directory();
if(writeDirectoryDB()<0) {
fprintf(stderr,"problem opening db for reading or writing\n");
exit(-1);
}
}
initAudioDriver();
initSigHandlers();
initInterfaces();
if((listenSocket = establish(port))<0) {
fprintf(stderr,"error binding port\n");
return -1;
}
initPlaylist();
initStats();
initBuffer();
daemon(0,0);
dup2(fileno(out),STDOUT_FILENO);
dup2(fileno(err),STDERR_FILENO);
fclose(stdin);
while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
nextSongInPlaylistIfPlayerStopped();
playerProcessMessages();
closeOldInterfaces();
}
playerStop(stderr);
clearPlaylist(stderr);
freeAllInterfaces();
close(listenSocket);
closeMp3Directory();
closeTables();
freeBuffer();
finishAudioDriver();
return 0;
}
.TH "Music Player Daemon" 1
.SH NAME
mpd \- A daemon for playing music (mp3, ogg vorbis, and flac)
.SH SYNOPSIS
.B mpd
<port> <music dir> <playlist dir> <log file> <error file>
.br
.B mpd
<config file>
.SH DESCRIPTION
A daemon for playing music (mp3, ogg vorbis, and flac). Music is played
through the server's audio device. The daemon stores info about all available
music, and this info can be easily searched and retrieved. Player control, info
retrieval, and playlist management can all be managed remotely.
Read more about MPD on http://www.musicpd.org
.SH PARAMETERS
Below are a list of paramters that can be specified in the config file. Each line in the config file should be of the form:
.br
parameter "value"
.TP
.B port <port>
This specifies the port that MPD listens on. This parameter is required. This is typically 2100.
.TP
.B music_directory <directory>
This specifies the directory where music is located. This paramter is required. The directory path should be an absolute path.
.TP
.B playlist_directory <directory>
This specifies the directory where saved playlists are stored. This paramter is required. The directory path should be an absolute path.
.TP
.B log_file <file>
This specifies where the log file should be located. This paramter is required. The file path should be an absolute path.
.TP
.B error_file <file>
This specifies where the error file should be located. This paramter is required. The file path should be an absolute path.
.TP
.B connection_timeout <seconds>
If a client does not send any new data in this time period, the connection is closed. The default is 60 seconds.
.TP
.B max_connections <int>
This specifies the maximum number of clients that can be connected to MPD. The default is 5 connections.
.TP
.B mixer_device <mixer dev>
This specifies which mixer to use. The default is /dev/mixer.
.TP
.B max_playlist_length <int>
This specifies the maximum number of songs that can be in the playlist. The default is 4096 songs.
.TP
.B buffer_before play <0-100%>
This specifies the amount of buffer that will be filled before a song begins playing. The default is 25%.
.TP
.B stop_on_error <yes or no>
This specifies wether playback should stop or goto the next song when an error occurs. The default is no.
.TP
.B max_command_list_size <size in kB>
This specifies the maximum size a command list can be (in kilobytes). The default is 2048 kilobytes.
.TP
.B max_output_buffer_size <size in kB>
This specifies the maximum size of the output buffer to a client (in kilobytes).
The default is 2048 kilobytes.
.TP
.B ao_driver <ao plugin>
This specifies the ao plugin to use for audio output. Typical values for
linux include "oss" and "alsa09". The default value is "default".
.TP
.B ao_driver_options <ao plugin options>
This specifies the options to use for the selected ao_driver. For oss, the
only option available is "dsp". For alsa09, the available options are:
"dev", "buf_size", and "periods". Options are assigned using "=" and ";" is
used to seperate options. An example for oss: "dsp=/dev/dsp". An example for
alsa09: "dev=hw:0,0;buf_size=4096". The default value is "".
.TP
.B save_absolute_paths_in_playlists <yes or no>
This specifies whether relative or absolute paths for song filenames are
used when saving playlists. The default value is "no".
.TP
.B bind_to_address <ip address or hostname or any>
This specifies which address mpd binds to and listens on. The default is "any",
which binds to all available addresses.
.SH FILES
A file is created in the playlist directory called ".mpddb". This file is used to store information about songs located in the music directory.
#include "myfprintf.h"
#include "interface.h"
#include <stdarg.h>
#include <sys/param.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define BUFFER_LENGTH MAXPATHLEN+1024
void myfprintf(FILE * fp, char * format, ... ) {
va_list arglist;
va_start(arglist,format);
if(fcntl(fileno(fp),F_GETFL) & O_NONBLOCK) {
char buffer[BUFFER_LENGTH+1];
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
interfacePrintWithFD(fileno(fp),buffer);
}
else {
vfprintf(fp,format,arglist);
}
va_end(arglist);
}
#ifndef MYFPRINTF_H
#define MYFPRINTF_H
#include <stdio.h>
void myfprintf(FILE * fp, char * format, ... );
#endif
/* the Music Player Daemon (MPD)
* (c)2003 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
*/
#ifdef HAVE_OGG
#include "ogg_decode.h"
#include "player.h"
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "buffer.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <vorbis/vorbisfile.h>
#include <time.h>
#include <ao/ao.h>
#define TIME_TELL_INTERVAL 0.2
#define CHECK_INPUT_FREQ 300 /* about once very 0.1 seconds */
#define INPUT_BUFFER_SIZE 80
int ogg_decode_pid = 0;
int ogg_decode_done = 0;
ao_device * ogg_device = NULL;
void ogg_decode_parentSigHandler(int sig) {
if(sig==SIGCHLD) {
if(ogg_decode_pid==wait3(NULL,WNOHANG,NULL)) {
ogg_decode_pid = 0;
ogg_decode_done = 1;
}
}
else if(sig==SIGTERM) {
int pid = ogg_decode_pid;
if(pid>0) kill(pid,SIGTERM);
if(ogg_device) ao_close(ogg_device);
exit(0);
}
}
/* ogg_decode w/ buffering
* this will fork another process
* child process does decoding
* parent process does buffering && playing audio
*/
int ogg_decode(char * file, FILE * in, FILE * out) {
OggVorbis_File vf;
ao_sample_format format;
float time_total;
FILE * oggfp;
Buffer * cb;
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if(!(oggfp = fopen(file,"r")) || ov_open(oggfp, &vf, NULL, 0) < 0) {
fprintf(stderr,"%s Input does not appear to be an Ogg bitstream.\n",PLAYER_ERROR);
fflush(stderr);
return PLAYER_EXIT_ERROR_FILE;
}
{
vorbis_info *vi=ov_info(&vf,-1);
format.bits = 16;
format.channels = vi->channels;
format.rate = vi->rate;
format.byte_format = AO_FMT_LITTLE;
}
time_total = ov_time_total(&vf,-1);
cb = getBuffer();
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
cb->finished = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = ogg_decode_parentSigHandler;
sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGTERM,&sa,NULL);
fflush(NULL);
ogg_decode_pid = fork();
if(ogg_decode_pid==0) {
/* CHILD */
int current_section;
int eof = 0;
struct timeval tv;
long ret;
tv.tv_sec = 0;
tv.tv_usec = 0;
fclose(in);
fclose(out);
while(!eof) {
if(cb->begin!=cb->end || !cb->wrap) {
ret = ov_read(&vf,cb->chunks[cb->end],CHUNK_SIZE,0,2,1,&current_section);
cb->times[cb->end] = ov_time_tell(&vf);
if(ret==0) eof = 1;
cb->end++;
if(cb->end>=BUFFERED_CHUNKS) {
cb->end = 0;
cb->wrap = 1;
}
}
else usleep(100);
}
ov_clear(&vf);
cb->finished = 1;
exit(0);
/* END OF CHILD */
}
else if(ogg_decode_pid<0) {
fprintf(stderr,"%s ogg_decode Problems fork'ing\n",COMMAND_RESPOND_ERROR);
return PLAYER_EXIT_ERROR_SYSTEM;
}
{
/* PARENT */
float elapsed = 0;
float last_tell = 0;
int pause = 0;
char input[INPUT_BUFFER_SIZE+1];
int playsPerChunk = CHUNK_SIZE/PLAY_SIZE;
int currentPlayChunk = 0;
int quit = 0;
fd_set fds;
struct timeval tv;
int checkInput = 0;
int pid;
tv.tv_sec = 0;
tv.tv_usec = 0;
ov_clear(&vf);
initAudio();
ogg_device = ao_open_live(audio_ao_driver_id,&format,
audio_ao_options);
if(ogg_device == NULL) {
audioError();
pid = ogg_decode_pid;
if(pid>0) kill(pid,SIGTERM);
return PLAYER_EXIT_ERROR_AUDIO;
}
fprintf(out,"%s\n",PLAYER_START);
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,time_total);
fflush(out);
while(ogg_decode_pid>0 && !cb->wrap && cb->end-cb->begin<buffered_before_play && !cb->finished) {
usleep(1000);
}
while(!quit) {
if(pause || checkInput%CHECK_INPUT_FREQ==0) {
FD_ZERO(&fds);
FD_SET(fileno(in),&fds);
fflush(in);
if(select(fileno(in)+1,&fds,NULL,NULL,&tv)) {
myFgets(input,INPUT_BUFFER_SIZE,in);
if(strcasecmp(PLAYER_PAUSE,input)==0) {
fprintf(out,"%s\n",PLAYER_PAUSE_GOT);
fflush(out);
pause = !pause;
}
}
checkInput = 1;
}
checkInput++;
if(pause) usleep(100);
else if(cb->begin!=cb->end || cb->wrap) {
if(currentPlayChunk==0) elapsed = cb->times[cb->begin];
ao_play(ogg_device,cb->chunks[cb->begin]+currentPlayChunk*PLAY_SIZE,PLAY_SIZE);
currentPlayChunk++;
if(currentPlayChunk>=playsPerChunk) {
currentPlayChunk=0;
cb->begin++;
if(cb->begin>=BUFFERED_CHUNKS) {
cb->begin = 0;
cb->wrap = 0;
}
}
if(elapsed-last_tell>=TIME_TELL_INTERVAL) {
last_tell = elapsed;
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,time_total);
fflush(out);
}
}
else if(ogg_decode_pid<=0 || cb->finished) {
quit = 1;
}
else usleep(200);
}
pid = ogg_decode_pid;
if(pid>0) kill(pid,SIGTERM);
ao_close(ogg_device);
finishAudio();
/* END OF PARENT */
}
return 0;
}
#endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "player.h"
#ifdef HAVE_MAD
#include "mp3_decode.h"
#endif
#ifdef HAVE_OGG
#include "ogg_decode.h"
#endif
#ifdef HAVE_OGG
#include "flac_decode.h"
#endif
#include "command.h"
#include "interface.h"
#include "playlist.h"
#include "ls.h"
#include "listen.h"
#include "path.h"
#include "myfprintf.h"
#include <stdio.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#define PLAYER_TYPE_MP3 0
#define PLAYER_TYPE_OGG 1
#define PLAYER_TYPE_FLAC 2
#define MAX_BUFFER_LENGTH 1024
int player_pid = 0;
int player_state = PLAYER_STATE_STOP;
int player_elapsedTime = 0;
int player_totalTime = 0;
int player_send = -1;
int player_recv = -1;
int player_leavePause = 1;
int player_leavePlay = 1;
char player_buffer[MAX_BUFFER_LENGTH+1];
int player_bufferLength = 0;
char player_currentSong[MAXPATHLEN+2] = "\0";
char player_error[2*MAXPATHLEN] = "\0";
void playerReset() {
player_pid = 0;
close(player_recv);
close(player_send);
player_leavePause = 1;
player_leavePlay = 1;
player_state = PLAYER_STATE_STOP;
player_currentSong[0] = '\0';
player_bufferLength = 0;
}
void player_sigHandler(int signal) {
if(signal==SIGCHLD) {
int status;
if(player_pid==wait3(&status,WNOHANG,NULL)) {
if(WEXITSTATUS(status)==PLAYER_EXIT_ERROR_FILE) {
strcpy(player_error,"problem with file: ");
strcat(player_error,player_currentSong);
}
else if(WEXITSTATUS(status)==PLAYER_EXIT_ERROR_AUDIO) {
strcpy(player_error,"problem opening audio device");
}
else if(WEXITSTATUS(status)==PLAYER_EXIT_ERROR_SYSTEM) {
strcpy(player_error,"system error while playing: ");
strcat(player_error,player_currentSong);
}
else if(WEXITSTATUS(status)) {
strcpy(player_error,"unkown error while playing: ");
strcat(player_error,player_currentSong);
}
playerReset();
}
}
}
int playerInit(char * file, int playerType) {
int fd_send[2], fd_recv[2];
player_elapsedTime = 0;
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_send)<0) {
fprintf(stderr,"%s player Problems socketpair'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(socketpair(AF_UNIX,SOCK_STREAM,0,fd_recv)<0) {
fprintf(stderr,"%s player Problems socketpair()'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
fflush(NULL);
player_pid = fork();
fcntl(player_recv,F_SETOWN,(int)getpid());
fcntl(player_recv,F_SETFL,fcntl(player_recv,F_GETFL) | O_ASYNC);
if(player_pid==0) {
FILE * in;
FILE * out;
int ret = 0;
close(listenSocket);
freeAllInterfaces();
close(fd_send[0]);
close(fd_recv[0]);
in = fdopen(fd_send[1],"r");
out = fdopen(fd_recv[1],"w");
#ifdef HAVE_MAD
if(playerType==PLAYER_TYPE_MP3 && (ret=mp3_decode(rmp2amp(file),in,out))!=0) {
fclose(in);
fclose(out);
exit(ret);
}
#endif
#ifdef HAVE_OGG
if(playerType==PLAYER_TYPE_OGG && (ret=ogg_decode(rmp2amp(file),in,out))!=0) {
fclose(in);
fclose(out);
exit(ret);
}
#endif
#ifdef HAVE_FLAC
if(playerType==PLAYER_TYPE_FLAC && (ret=flac_decode(rmp2amp(file),in,out)!=0)) {
fclose(in);
fclose(out);
exit(ret);
}
#endif
fclose(in);
fclose(out);
exit(0);
}
else if(player_pid<0) {
fprintf(stderr,"%s player Problems fork()'ing\n",COMMAND_RESPOND_ERROR);
player_pid = 0;
player_leavePlay = 1;
close(fd_send[0]);
close(fd_send[1]);
close(fd_recv[0]);
close(fd_recv[1]);
return -1;
}
close(fd_send[1]);
close(fd_recv[1]);
player_send = fd_send[0];
player_recv = fd_recv[0];
return 0;
}
int playerPlay(FILE * fp, char * file) {
int playerType;
if(fp==NULL) fp=stderr;
if(0);
#ifdef HAVE_MAD
else if(isMp3(file)) playerType = PLAYER_TYPE_MP3;
#endif
#ifdef HAVE_OGG
else if(isOgg(file)) playerType = PLAYER_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
else if(isFlac(file)) playerType = PLAYER_TYPE_FLAC;
#endif
else {
snprintf(player_error,sizeof(player_error),"\"%s\" is not a file or unknown file type",file);
return 0;
}
if(playerStop(fp)<0) return -1;
player_state = PLAYER_STATE_PLAY;
player_currentSong[0] = '\0';
strcpy(player_currentSong,file);
player_leavePlay = 0;
if(playerInit(file,playerType)<0) {
myfprintf(fp,"%s problems init'ing player\n",COMMAND_RESPOND_ERROR);
return -1;
}
while(player_pid>0) {
playerProcessMessages();
if(player_leavePlay) break;
usleep(1);
}
return 0;
}
int playerStop(FILE * fp) {
int pid = player_pid;
if(pid>0) {
kill(pid,SIGTERM);
while(player_pid>0) usleep(1);
}
player_state = PLAYER_STATE_STOP;
return 0;
}
int playerPause(FILE * fp) {
char string[1024];
if(player_pid>0) {
player_leavePause = 0;
sprintf(string,"%s\n",PLAYER_PAUSE);
if(write(player_send,string,strlen(string))<0) {
myfprintf(fp,"%s problems write'ing\n",COMMAND_RESPOND_ERROR);
}
if(player_state==PLAYER_STATE_PLAY) {
player_state = PLAYER_STATE_PAUSE;
}
else if(player_state==PLAYER_STATE_PAUSE) {
player_state = PLAYER_STATE_PLAY;
}
while(!player_leavePause) {
playerProcessMessages();
usleep(1);
}
}
return 0;
}
int playerReadline() {
fd_set fdsr;
struct timeval tv;
FD_ZERO(&fdsr);
FD_SET(player_recv,&fdsr);
tv.tv_sec = tv.tv_usec = 0;
if(select(player_recv+1,&fdsr,NULL,NULL,&tv)==1) {
int rc;
while(1) {
rc = read(player_recv,player_buffer+player_bufferLength,1);
if(rc<=0) return 0;
player_buffer[player_bufferLength+1] = '\0';
if(player_buffer[player_bufferLength]=='\0' || player_buffer[player_bufferLength]=='\n' || player_bufferLength == MAX_BUFFER_LENGTH) {
player_buffer[player_bufferLength] = '\0';
player_bufferLength = 0;
return -1;
}
player_bufferLength++;
}
}
return 0;
}
void playerProcessMessages() {
if(player_pid>0) {
while(playerReadline()) {
char * c[4];
c[0] = strtok(player_buffer," ");
if(c[0]) {
if(0==strcmp(c[0],PLAYER_TIME)) {
c[1] = strtok(NULL," ");
c[2] = strtok(NULL," ");
player_totalTime = atof(c[2])+0.5;
player_elapsedTime = atof(c[1])+0.5;
player_leavePlay = 1;
}
else if(0==strcmp(c[0],PLAYER_ERROR)) {
myfprintf(stderr,"player error: file \"%s\" : %s\n",player_currentSong,c[1]);
player_leavePlay = 1;
}
else if(0==strcmp(c[0],PLAYER_PAUSE_GOT)) {
player_leavePause = 1;
}
}
}
}
}
int getPlayerElapsedTime() {
return player_elapsedTime;
}
int getPlayerTotalTime() {
return player_totalTime;
}
int getPlayerState() {
return player_state;
}
void clearPlayerError() {
player_error[0] = '\0';
}
char * getPlayerError() {
return player_error;
}
/* the Music Player Daemon (MPD)
* (c)2003 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 "playlist.h"
#include "player.h"
#include "command.h"
#include "ls.h"
#include "tag.h"
#include "conf.h"
#include "directory.h"
#include "stats.h"
#include "myfprintf.h"
#include "path.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#define BITS_FOR_VERSION 31
#define PLAYLIST_COMMENT '#'
#define PLAYLIST_STATE_STOP 0
#define PLAYLIST_STATE_PLAY 1
#define PLAYLIST_PREV_UNLESS_ELAPSED 10
/* if a song is played more than PREV_UNLESS_ELAPSED seconds,
* 'previous' restarts playing this song ('play it again, sam')
* */
Playlist playlist;
int playlist_state = PLAYLIST_STATE_STOP;
int playlist_max_length;
int playlist_stopOnError;
int playlist_saveAbsolutePaths;
void incrPlaylistVersion() {
static unsigned long max = ((unsigned long)1<<BITS_FOR_VERSION)-1;
playlist.version++;
if(playlist.version>=max) playlist.version = 0;
}
void initPlaylist() {
char * test;
playlist.length = 0;
playlist.repeat = 0;
playlist.version = 0;
playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10);
if(*test!='\0') {
fprintf(stderr,"max playlist length \"%s\" is not an integer\n",(getConf())[CONF_MAX_PLAYLIST_LENGTH]);
exit(-1);
}
if(strcmp("yes",(getConf())[CONF_STOP_ON_ERROR])==0) {
playlist_stopOnError = 1;
}
else if(strcmp("no",(getConf())[CONF_STOP_ON_ERROR])==0) {
playlist_stopOnError = 0;
}
else {
fprintf(stderr,"stop_on_error \"%s\" is not yes or no\n",(getConf())[CONF_STOP_ON_ERROR]);
exit(-1);
}
if(strcmp("yes",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
==0) {
playlist_saveAbsolutePaths = 1;
}
else if(strcmp("no",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
==0) {
playlist_saveAbsolutePaths = 0;
}
else {
fprintf(stderr,"save_absolute_paths_in_playlist \"%s\" is not yes or no\n",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]);
exit(-1);
}
playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
memset(playlist.songs,(int)NULL,sizeof(char *)*playlist_max_length);
}
int clearPlaylist(FILE * fp) {
int i;
if(stopPlaylist(fp)<0) return -1;
for(i=0;i<playlist.length;i++) playlist.songs[i] = NULL;
playlist.length = 0;
incrPlaylistVersion();
return 0;
}
int addToPlaylist(FILE * fp, char * file) {
Song * song;
if(!(song = getSong(file))) {
myfprintf(fp,"%s \"%s\" is not in the music db\n",COMMAND_RESPOND_ERROR,file);
return -1;
}
if(playlist.length==playlist_max_length) {
myfprintf(fp,"%s playlist is at the max size\n",COMMAND_RESPOND_ERROR);
return -1;
}
playlist.songs[playlist.length] = song;
playlist.length++;
incrPlaylistVersion();
return 0;
}
int showPlaylist(FILE * fp) {
int i;
for(i=0;i<playlist.length;i++) {
myfprintf(fp,"%i \"%s\"\n",i,(playlist.songs[i])->file);
}
return 0;
}
int playlistInfo(FILE * fp,int song) {
MpdTag * tag;
int i;
int begin = 0;
int end = playlist.length;
if(song>=0) {
begin = song;
end = song+1;
}
if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
return -1;
}
for(i=begin;i<end;i++) {
myfprintf(fp,"file: %s\n",(playlist.songs[i])->file);
if((tag = (playlist.songs[i])->tag)) {
printMpdTag(fp,tag);
}
}
return 0;
}
void swapSongs(int song1, int song2) {
Song * temp;
temp = playlist.songs[song1];
playlist.songs[song1] = playlist.songs[song2];
playlist.songs[song2] = temp;
}
int deleteFromPlaylist(FILE * fp, int song) {
int i;
if(song<0) {
myfprintf(fp,"%s need a positive interger\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
return -1;
}
for(i=song;i<playlist.length-1;i++) {
playlist.songs[i] = playlist.songs[i+1];
}
playlist.songs[playlist.length-1] = NULL;
playlist.length--;
incrPlaylistVersion();
if(playlist_state!=PLAYLIST_STATE_STOP && playlist.current==song) {
if(playlist.current>=playlist.length) return playerStop(fp);
else return playPlaylist(fp,playlist.current);
}
else if(playlist_state!=PLAYLIST_STATE_STOP && playlist.current>song) {
playlist.current--;
}
return 0;
}
void deleteASongFromPlaylist(Song * song) {
int i;
for(i=0;i<playlist.length;i++) {
if(song==playlist.songs[i]) {
deleteFromPlaylist(stderr,i);
}
}
}
void deleteSongsFromPlaylist(SongList * songList) {
ListNode * node = songList->firstNode;
Song * song;
while(node) {
song = (Song *)node->data;
deleteASongFromPlaylist(song);
node = node->nextNode;
}
}
int stopPlaylist(FILE * fp) {
if(playerStop(fp)<0) return -1;
playlist_state = PLAYLIST_STATE_STOP;
stats.playTime+=getPlayerElapsedTime();
return 0;
}
int playPlaylist(FILE * fp, int song) {
clearPlayerError();
if(song<0) {
myfprintf(fp,"%s need a positive interger\n",COMMAND_RESPOND_ERROR);
playlist_state = PLAYLIST_STATE_STOP;
return -1;
}
if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
playlist_state = PLAYLIST_STATE_STOP;
return -1;
}
if(playerStop(fp)<0) return -1;
playlist.current = song;
playlist_state = PLAYLIST_STATE_PLAY;
stats.songsPlayed++;
if(playerPlay(fp,(playlist.songs[song])->file)<0) {
stopPlaylist(stderr);
return -1;
}
return 0;
}
void nextSongInPlaylistIfPlayerStopped() {
if(playlist_state==PLAYLIST_STATE_PLAY && getPlayerState()==PLAYER_STATE_STOP) {
if(playlist_stopOnError && strlen(getPlayerError())) {
stopPlaylist(stderr);
}
else nextSongInPlaylist(stderr);
}
}
int nextSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) {
myfprintf(fp,"%s not currently playing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(playlist.current<playlist.length-1) {
stats.playTime+=getPlayerElapsedTime();
return playPlaylist(fp,playlist.current+1);
}
else if(playlist.repeat) {
stats.playTime+=getPlayerElapsedTime();
return playPlaylist(fp,0);
}
else return stopPlaylist(fp);;
return 0;
}
int getPlaylistRepeatStatus() {
return playlist.repeat;
}
int setPlaylistRepeatStatus(FILE * fp, int status) {
if(status!=0 && status!=1) {
myfprintf(fp,"%s \"%i\" is not 0 or 1\n",COMMAND_RESPOND_ERROR,status);
return -1;
}
playlist.repeat = status;
return 0;
}
int previousSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) {
myfprintf(fp,"%s not currently playing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if (getPlayerElapsedTime()>PLAYLIST_PREV_UNLESS_ELAPSED) {
return playPlaylist(fp,playlist.current);
}
else {
if(playlist.current>0) {
return playPlaylist(fp,playlist.current-1);
}
else if(playlist.repeat) {
return playPlaylist(fp,playlist.length-1);
}
else {
return playPlaylist(fp,playlist.current);
}
}
return 0;
}
int shufflePlaylist(FILE * fp) {
int i;
int ri;
srand(time(NULL));
for(i=0;i<playlist.length;i++) {
ri = rand()%playlist.length;
swapSongs(i,ri);
if(i==playlist.current) playlist.current=ri;
else if(ri==playlist.current) playlist.current=i;
}
incrPlaylistVersion();
return 0;
}
int deletePlaylist(FILE * fp, char * file) {
struct stat st;
if(stat(file,&st)<0) {
myfprintf(fp,"%s problems stat'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(!S_ISREG(st.st_mode)) {
myfprintf(fp,"%s not a file\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(unlink(file)<0) {
myfprintf(fp,"%s problems deleting file\n",COMMAND_RESPOND_ERROR);
return -1;
}
return 0;
}
int savePlaylist(FILE * fp, char * file) {
FILE * fileP;
int i;
struct stat st;
if(0==stat(file,&st)) {
myfprintf(fp,"%s A file or direcory already exists with the name \"%s\"\n",COMMAND_RESPOND_ERROR,file);
return -1;
}
if((fileP = fopen(file,"w"))==NULL) {
myfprintf(fp,"%s Problems opening file\n",COMMAND_RESPOND_ERROR);
return -1;
}
for(i=0;i<playlist.length;i++) {
if(playlist_saveAbsolutePaths) {
fprintf(fileP,"%s%s\n",musicDir,
(playlist.songs[i])->file);
}
else {
fprintf(fileP,"%s\n",(playlist.songs[i])->file);
}
}
fclose(fileP);
return 0;
}
int loadPlaylist(FILE * fp, char * file) {
FILE * fileP;
char s[MAXPATHLEN+1];
int slength = 0;
if((fileP = fopen(file,"r"))==NULL) {
myfprintf(fp,"%s Problems opening file \"%s\"\n",COMMAND_RESPOND_ERROR,file);
return -1;
}
while((s[slength] = fgetc(fileP))!=EOF) {
if(s[slength]=='\n' || s[slength]=='\0') {
s[slength] = '\0';
if(strncmp(s,musicDir,strlen(musicDir))==0) {
strcpy(s,&(s[strlen(musicDir)]));
}
slength = 0;
if(s[0]==PLAYLIST_COMMENT && !getSong(s)) continue;
if((addToPlaylist(fp,s))<0) {
return -1;
}
}
else if(slength==MAXPATHLEN) {
s[slength] = '\0';
myfprintf(fp,"%s \"%s\" too long\n",COMMAND_RESPOND_ERROR,s);
return -1;
}
else {
slength++;
}
}
fclose(fileP);
return 0;
}
#include "sig_handlers.h"
#include "player.h"
#include <signal.h>
void initSigHandlers() {
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sigaction(SIGIO,&sa,NULL);
sa.sa_handler = player_sigHandler;
sigaction(SIGCHLD,&sa,NULL);
}
#ifndef SIG_HANDLERS_H
#define SIG_HANDLERS_H
void initSigHandlers();
#endif
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
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 \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.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 \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
$(mpd_headers)
CFLAGS = @CFLAGS@ $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB)
# Makefile.in generated by automake 1.6.3 from Makefile.am.
# @configure_input@
# Copyright 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002
# Free Software Foundation, Inc.
# This Makefile.in is free software; the Free Software Foundation
# gives unlimited permission to copy and/or distribute it,
# with or without modifications, as long as this notice is preserved.
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
# PARTICULAR PURPOSE.
@SET_MAKE@
SHELL = @SHELL@
srcdir = @srcdir@
top_srcdir = @top_srcdir@
VPATH = @srcdir@
prefix = @prefix@
exec_prefix = @exec_prefix@
bindir = @bindir@
sbindir = @sbindir@
libexecdir = @libexecdir@
datadir = @datadir@
sysconfdir = @sysconfdir@
sharedstatedir = @sharedstatedir@
localstatedir = @localstatedir@
libdir = @libdir@
infodir = @infodir@
mandir = @mandir@
includedir = @includedir@
oldincludedir = /usr/include
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkgincludedir = $(includedir)/@PACKAGE@
top_builddir = ..
ACLOCAL = @ACLOCAL@
AUTOCONF = @AUTOCONF@
AUTOMAKE = @AUTOMAKE@
AUTOHEADER = @AUTOHEADER@
am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
INSTALL_DATA = @INSTALL_DATA@
install_sh_DATA = $(install_sh) -c -m 644
install_sh_PROGRAM = $(install_sh) -c
install_sh_SCRIPT = $(install_sh) -c
INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_HEADER = $(INSTALL_DATA)
transform = @program_transform_name@
NORMAL_INSTALL = :
PRE_INSTALL = :
POST_INSTALL = :
NORMAL_UNINSTALL = :
PRE_UNINSTALL = :
POST_UNINSTALL = :
host_alias = @host_alias@
host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
ID3_LIB = @ID3_LIB@
ID3_SUBDIR = @ID3_SUBDIR@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBFLAC_CFLAGS = @LIBFLAC_CFLAGS@
LIBFLAC_LIBS = @LIBFLAC_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
MPD_LIBS = @MPD_LIBS@
OBJDUMP = @OBJDUMP@
OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
VORBISFILE_LIBS = @VORBISFILE_LIBS@
VORBIS_CFLAGS = @VORBIS_CFLAGS@
VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
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 \
audio.h playerData.h stats.h myfprintf.h sig_handlers.h decode.h log.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 \
audio.c playerData.c stats.c myfprintf.c sig_handlers.c decode.c log.c \
$(mpd_headers)
CFLAGS = @CFLAGS@ $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB)
subdir = src
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_CLEAN_FILES =
bin_PROGRAMS = mpd$(EXEEXT)
PROGRAMS = $(bin_PROGRAMS)
am__objects_1 =
am_mpd_OBJECTS = main.$(OBJEXT) buffer2array.$(OBJEXT) \
interface.$(OBJEXT) command.$(OBJEXT) playlist.$(OBJEXT) \
ls.$(OBJEXT) song.$(OBJEXT) list.$(OBJEXT) directory.$(OBJEXT) \
tables.$(OBJEXT) utils.$(OBJEXT) path.$(OBJEXT) \
mp3_decode.$(OBJEXT) tag.$(OBJEXT) player.$(OBJEXT) \
listen.$(OBJEXT) conf.$(OBJEXT) ogg_decode.$(OBJEXT) \
volume.$(OBJEXT) flac_decode.$(OBJEXT) audio.$(OBJEXT) \
playerData.$(OBJEXT) stats.$(OBJEXT) myfprintf.$(OBJEXT) \
sig_handlers.$(OBJEXT) decode.$(OBJEXT) log.$(OBJEXT) \
$(am__objects_1)
mpd_OBJECTS = $(am_mpd_OBJECTS)
mpd_DEPENDENCIES =
mpd_LDFLAGS =
DEFS = @DEFS@
DEFAULT_INCLUDES = -I. -I$(srcdir)
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/audio.Po ./$(DEPDIR)/buffer2array.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/command.Po ./$(DEPDIR)/conf.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/decode.Po ./$(DEPDIR)/directory.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/flac_decode.Po ./$(DEPDIR)/interface.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/list.Po ./$(DEPDIR)/listen.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/log.Po ./$(DEPDIR)/ls.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/main.Po ./$(DEPDIR)/mp3_decode.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/myfprintf.Po ./$(DEPDIR)/ogg_decode.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/path.Po ./$(DEPDIR)/player.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/playerData.Po ./$(DEPDIR)/playlist.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/sig_handlers.Po ./$(DEPDIR)/song.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/stats.Po ./$(DEPDIR)/tables.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/tag.Po ./$(DEPDIR)/utils.Po \
@AMDEP_TRUE@ ./$(DEPDIR)/volume.Po
COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
$(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
LTCOMPILE = $(LIBTOOL) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) \
$(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
CCLD = $(CC)
LINK = $(LIBTOOL) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(AM_LDFLAGS) $(LDFLAGS) -o $@
DIST_SOURCES = $(mpd_SOURCES)
RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
uninstall-info-recursive all-recursive install-data-recursive \
install-exec-recursive installdirs-recursive install-recursive \
uninstall-recursive check-recursive installcheck-recursive
DIST_COMMON = Makefile.am Makefile.in
DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(mpd_SOURCES)
all: all-recursive
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
$(srcdir)/Makefile.in: Makefile.am $(top_srcdir)/configure.in $(ACLOCAL_M4)
cd $(top_srcdir) && \
$(AUTOMAKE) --foreign src/Makefile
Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)
binPROGRAMS_INSTALL = $(INSTALL_PROGRAM)
install-binPROGRAMS: $(bin_PROGRAMS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(bindir)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
p1=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
if test -f $$p \
|| test -f $$p1 \
; then \
f=`echo "$$p1" | sed 's,^.*/,,;$(transform);s/$$/$(EXEEXT)/'`; \
echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f"; \
$(INSTALL_PROGRAM_ENV) $(LIBTOOL) --mode=install $(binPROGRAMS_INSTALL) $$p $(DESTDIR)$(bindir)/$$f; \
else :; fi; \
done
uninstall-binPROGRAMS:
@$(NORMAL_UNINSTALL)
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo "$$p" | sed 's,^.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/'`; \
echo " rm -f $(DESTDIR)$(bindir)/$$f"; \
rm -f $(DESTDIR)$(bindir)/$$f; \
done
clean-binPROGRAMS:
@list='$(bin_PROGRAMS)'; for p in $$list; do \
f=`echo $$p|sed 's/$(EXEEXT)$$//'`; \
echo " rm -f $$p $$f"; \
rm -f $$p $$f ; \
done
mpd$(EXEEXT): $(mpd_OBJECTS) $(mpd_DEPENDENCIES)
@rm -f mpd$(EXEEXT)
$(LINK) $(mpd_LDFLAGS) $(mpd_OBJECTS) $(mpd_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT) core *.core
distclean-compile:
-rm -f *.tab.c
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/audio.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/buffer2array.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/conf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/directory.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/flac_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/interface.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/list.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/listen.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/log.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ls.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mp3_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/myfprintf.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ogg_decode.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/path.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/player.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playerData.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/playlist.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sig_handlers.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/song.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stats.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tables.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tag.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/utils.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/volume.Po@am__quote@
distclean-depend:
-rm -rf ./$(DEPDIR)
.c.o:
@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(COMPILE) -c `test -f '$<' || echo '$(srcdir)/'`$<
.c.obj:
@AMDEP_TRUE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Po' tmpdepfile='$(DEPDIR)/$*.TPo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(COMPILE) -c `cygpath -w $<`
.c.lo:
@AMDEP_TRUE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
@AMDEP_TRUE@ depfile='$(DEPDIR)/$*.Plo' tmpdepfile='$(DEPDIR)/$*.TPlo' @AMDEPBACKSLASH@
@AMDEP_TRUE@ $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
$(LTCOMPILE) -c -o $@ `test -f '$<' || echo '$(srcdir)/'`$<
CCDEPMODE = @CCDEPMODE@
mostlyclean-libtool:
-rm -f *.lo
clean-libtool:
-rm -rf .libs _libs
distclean-libtool:
-rm -f libtool
uninstall-info-am:
# This directory's subdirectories are mostly independent; you can cd
# into them and run `make' without going through this Makefile.
# To change the values of `make' variables: instead of editing Makefiles,
# (1) if the variable is set in `config.status', edit `config.status'
# (which will cause the Makefiles to be regenerated when you run `make');
# (2) otherwise, pass the desired values on the `make' command line.
$(RECURSIVE_TARGETS):
@set fnord $$MAKEFLAGS; amf=$$2; \
dot_seen=no; \
target=`echo $@ | sed s/-recursive//`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
dot_seen=yes; \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done; \
if test "$$dot_seen" = "no"; then \
$(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
fi; test -z "$$fail"
mostlyclean-recursive clean-recursive distclean-recursive \
maintainer-clean-recursive:
@set fnord $$MAKEFLAGS; amf=$$2; \
dot_seen=no; \
case "$@" in \
distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
*) list='$(SUBDIRS)' ;; \
esac; \
rev=''; for subdir in $$list; do \
if test "$$subdir" = "."; then :; else \
rev="$$subdir $$rev"; \
fi; \
done; \
rev="$$rev ."; \
target=`echo $@ | sed s/-recursive//`; \
for subdir in $$rev; do \
echo "Making $$target in $$subdir"; \
if test "$$subdir" = "."; then \
local_target="$$target-am"; \
else \
local_target="$$target"; \
fi; \
(cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
|| case "$$amf" in *=*) exit 1;; *k*) fail=yes;; *) exit 1;; esac; \
done && test -z "$$fail"
tags-recursive:
list='$(SUBDIRS)'; for subdir in $$list; do \
test "$$subdir" = . || (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
done
ETAGS = etags
ETAGSFLAGS =
tags: TAGS
ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
mkid -fID $$unique
TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
$(TAGS_FILES) $(LISP)
tags=; \
here=`pwd`; \
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -f $$subdir/TAGS && tags="$$tags -i $$here/$$subdir/TAGS"; \
fi; \
done; \
list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
unique=`for i in $$list; do \
if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
done | \
$(AWK) ' { files[$$0] = 1; } \
END { for (i in files) print i; }'`; \
test -z "$(ETAGS_ARGS)$$tags$$unique" \
|| $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
$$tags $$unique
GTAGS:
here=`$(am__cd) $(top_builddir) && pwd` \
&& cd $(top_srcdir) \
&& gtags -i $(GTAGS_ARGS) $$here
distclean-tags:
-rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH
DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
top_distdir = ..
distdir = $(top_distdir)/$(PACKAGE)-$(VERSION)
distdir: $(DISTFILES)
@list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
if test "$$dir" != "$$file" && test "$$dir" != "."; then \
dir="/$$dir"; \
$(mkinstalldirs) "$(distdir)$$dir"; \
else \
dir=''; \
fi; \
if test -d $$d/$$file; then \
if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
cp -pR $(srcdir)/$$file $(distdir)$$dir || exit 1; \
fi; \
cp -pR $$d/$$file $(distdir)$$dir || exit 1; \
else \
test -f $(distdir)/$$file \
|| cp -p $$d/$$file $(distdir)/$$file \
|| exit 1; \
fi; \
done
list='$(SUBDIRS)'; for subdir in $$list; do \
if test "$$subdir" = .; then :; else \
test -d $(distdir)/$$subdir \
|| mkdir $(distdir)/$$subdir \
|| exit 1; \
(cd $$subdir && \
$(MAKE) $(AM_MAKEFLAGS) \
top_distdir="$(top_distdir)" \
distdir=../$(distdir)/$$subdir \
distdir) \
|| exit 1; \
fi; \
done
check-am: all-am
check: check-recursive
all-am: Makefile $(PROGRAMS)
installdirs: installdirs-recursive
installdirs-am:
$(mkinstalldirs) $(DESTDIR)$(bindir)
install: install-recursive
install-exec: install-exec-recursive
install-data: install-data-recursive
uninstall: uninstall-recursive
install-am: all-am
@$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
installcheck: installcheck-recursive
install-strip:
$(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
INSTALL_STRIP_FLAG=-s \
`test -z '$(STRIP)' || \
echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
mostlyclean-generic:
clean-generic:
distclean-generic:
-rm -f Makefile $(CONFIG_CLEAN_FILES)
maintainer-clean-generic:
@echo "This command is intended for maintainers to use"
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive
distclean-am: clean-am distclean-compile distclean-depend \
distclean-generic distclean-libtool distclean-tags
dvi: dvi-recursive
dvi-am:
info: info-recursive
info-am:
install-data-am:
install-exec-am: install-binPROGRAMS
install-info: install-info-recursive
install-man:
installcheck-am:
maintainer-clean: maintainer-clean-recursive
maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
uninstall-am: uninstall-binPROGRAMS uninstall-info-am
uninstall-info: uninstall-info-recursive
.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool clean-recursive \
distclean distclean-compile distclean-depend distclean-generic \
distclean-libtool distclean-recursive distclean-tags distdir \
dvi dvi-am dvi-recursive info info-am info-recursive install \
install-am install-binPROGRAMS install-data install-data-am \
install-data-recursive install-exec install-exec-am \
install-exec-recursive install-info install-info-am \
install-info-recursive install-man install-recursive \
install-strip installcheck installcheck-am installdirs \
installdirs-am installdirs-recursive maintainer-clean \
maintainer-clean-generic maintainer-clean-recursive mostlyclean \
mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
mostlyclean-recursive tags tags-recursive uninstall \
uninstall-am uninstall-binPROGRAMS uninstall-info-am \
uninstall-info-recursive uninstall-recursive
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
...@@ -18,12 +18,19 @@ ...@@ -18,12 +18,19 @@
#include "audio.h" #include "audio.h"
#include "conf.h" #include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
int audio_ao_driver_id; int audio_ao_driver_id;
ao_option * audio_ao_options; ao_option * audio_ao_options;
AudioFormat audio_format;
ao_device * audio_device = NULL;
void initAudioDriver() { void initAudioDriver() {
ao_info * ai; ao_info * ai;
char * dup; char * dup;
...@@ -43,13 +50,13 @@ void initAudioDriver() { ...@@ -43,13 +50,13 @@ void initAudioDriver() {
} }
else if((audio_ao_driver_id = else if((audio_ao_driver_id =
ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) { ao_driver_id((getConf())[CONF_AO_DRIVER]))<0) {
fprintf(stderr,"\"%s\" is not a valid ao driver\n", ERROR1("\"%s\" is not a valid ao driver\n",
(getConf())[CONF_AO_DRIVER]); (getConf())[CONF_AO_DRIVER]);
exit(-1); exit(-1);
} }
if((ai = ao_driver_info(audio_ao_driver_id))==NULL) { if((ai = ao_driver_info(audio_ao_driver_id))==NULL) {
fprintf(stderr,"problems getting ao_driver_info\n"); ERROR0("problems getting ao_driver_info\n");
exit(-1); exit(-1);
} }
...@@ -61,27 +68,26 @@ void initAudioDriver() { ...@@ -61,27 +68,26 @@ void initAudioDriver() {
stk2 = NULL; stk2 = NULL;
key = strtok_r(n1,"=",&stk2); key = strtok_r(n1,"=",&stk2);
if(!key) { if(!key) {
fprintf(stderr,"problems parsing " ERROR1("problems parsing "
"ao_driver_options \"%s\"\n", n1); "ao_driver_options \"%s\"\n", n1);
exit(-1); exit(-1);
} }
/*found = 0; /*found = 0;
for(i=0;i<ai->option_count;i++) { for(i=0;i<ai->option_count;i++) {
printf("option: %s\n",ai->options[i]);
if(strcmp(ai->options[i],key)==0) { if(strcmp(ai->options[i],key)==0) {
found = 1; found = 1;
break; break;
} }
} }
if(!found) { if(!found) {
fprintf(stderr,"\"%s\" is not an option for " ERROR2("\"%s\" is not an option for "
"\"%s\" ao driver\n",key, "\"%s\" ao driver\n",key,
ai->short_name); ai->short_name);
exit(-1); exit(-1);
}*/ }*/
value = strtok_r(NULL,"",&stk2); value = strtok_r(NULL,"",&stk2);
if(!value) { if(!value) {
fprintf(stderr,"problems parsing " ERROR1("problems parsing "
"ao_driver_options \"%s\"\n", n1); "ao_driver_options \"%s\"\n", n1);
exit(-1); exit(-1);
} }
...@@ -90,33 +96,75 @@ void initAudioDriver() { ...@@ -90,33 +96,75 @@ void initAudioDriver() {
} }
} }
free(dup); free(dup);
ao_shutdown();
} }
void finishAudioDriver() { void finishAudioDriver() {
ao_free_options(audio_ao_options); ao_free_options(audio_ao_options);
ao_shutdown();
} }
void initAudio() { int initAudio(AudioFormat * audioFormat) {
ao_initialize(); ao_sample_format format;
if(audio_device) {
if(audio_format.bits!=audioFormat->bits ||
audio_format.sampleRate!=audioFormat->sampleRate ||
audio_format.channels!=audioFormat->channels) {
finishAudio();
}
}
if(!audio_device) {
format.bits = audioFormat->bits;
format.rate = audioFormat->sampleRate;
format.byte_format = AO_FMT_LITTLE;
format.channels = audioFormat->channels;
audio_format.bits = format.bits;
audio_format.sampleRate = format.rate;
audio_format.channels = format.channels;
blockSignals();
audio_device = ao_open_live(audio_ao_driver_id, &format,
audio_ao_options);
if(audio_device==NULL) {
unblockSignals();
audioError();
return -1;
}
unblockSignals();
}
return 0;
}
void playAudio(char * playChunk, int size) {
assert(audio_device!=NULL);
ao_play(audio_device,playChunk,size);
} }
void finishAudio() { void finishAudio() {
ao_shutdown(); if(audio_device) {
blockSignals();
ao_close(audio_device);
audio_device = NULL;
unblockSignals();
}
} }
void audioError() { void audioError() {
fprintf(stderr,"Error opening audio device\n"); ERROR0("Error opening audio device\n");
if(errno==AO_ENOTLIVE) { if(errno==AO_ENOTLIVE) {
fprintf(stderr,"not a live ao device\n"); ERROR0("not a live ao device\n");
} }
else if(errno==AO_EOPENDEVICE) { else if(errno==AO_EOPENDEVICE) {
fprintf(stderr,"not able to open audio device\n"); ERROR0("not able to open audio device\n");
} }
else if(errno==AO_EBADOPTION) { else if(errno==AO_EBADOPTION) {
fprintf(stderr,"bad driver option\n"); ERROR0("bad driver option\n");
} }
perror("ao error");
fflush(stderr);
} }
...@@ -19,11 +19,17 @@ ...@@ -19,11 +19,17 @@
#ifndef AUDIO_H #ifndef AUDIO_H
#define AUDIO_H #define AUDIO_H
#define AUDIO_AO_DRIVER_DEFAULT "default"
#include <stdio.h> #include <stdio.h>
#include <ao/ao.h> #include <ao/ao.h>
#define AUDIO_AO_DRIVER_DEFAULT "default"
typedef struct _AudioFormat {
int channels;
int sampleRate;
int bits;
} AudioFormat;
extern int audio_ao_driver_id; extern int audio_ao_driver_id;
extern ao_option * audio_ao_options; extern ao_option * audio_ao_options;
...@@ -31,7 +37,9 @@ void initAudioDriver(); ...@@ -31,7 +37,9 @@ void initAudioDriver();
void finishAudioDriver(); void finishAudioDriver();
void initAudio(); int initAudio(AudioFormat * audioFormat);
void playAudio(char * playChunk,int size);
void finishAudio(); void finishAudio();
......
...@@ -56,20 +56,24 @@ ...@@ -56,20 +56,24 @@
#define COMMAND_LISTALL "listall" #define COMMAND_LISTALL "listall"
#define COMMAND_VOLUME "volume" #define COMMAND_VOLUME "volume"
#define COMMAND_REPEAT "repeat" #define COMMAND_REPEAT "repeat"
#define COMMAND_RANDOM "random"
#define COMMAND_STATS "stats" #define COMMAND_STATS "stats"
#define COMMAND_CLEAR_ERROR "clearerror" #define COMMAND_CLEAR_ERROR "clearerror"
#define COMMAND_LIST "list" #define COMMAND_LIST "list"
#define COMMAND_MOVE "move"
#define COMMAND_SWAP "swap"
#define COMMAND_SEEK "seek"
#define COMMAND_STATUS_VOLUME "volume" #define COMMAND_STATUS_VOLUME "volume"
#define COMMAND_STATUS_STATE "state" #define COMMAND_STATUS_STATE "state"
#define COMMAND_STATUS_REPEAT "repeat" #define COMMAND_STATUS_REPEAT "repeat"
#define COMMAND_STATUS_RANDOM "random"
#define COMMAND_STATUS_PLAYLIST "playlist" #define COMMAND_STATUS_PLAYLIST "playlist"
#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
#define COMMAND_STATUS_SONG "song" #define COMMAND_STATUS_SONG "song"
#define COMMAND_STATUS_TIME "time" #define COMMAND_STATUS_TIME "time"
#define COMMAND_STATUS_ERROR "error" #define COMMAND_STATUS_ERROR "error"
extern Playlist playlist;
int commandStatus(FILE * fp,int argArrayLength, char ** argArray) { int commandStatus(FILE * fp,int argArrayLength, char ** argArray) {
char * state = NULL; char * state = NULL;
if(argArrayLength!=1) { if(argArrayLength!=1) {
...@@ -77,6 +81,7 @@ int commandStatus(FILE * fp,int argArrayLength, char ** argArray) { ...@@ -77,6 +81,7 @@ int commandStatus(FILE * fp,int argArrayLength, char ** argArray) {
return -1; return -1;
} }
playPlaylistIfPlayerStopped();
switch(getPlayerState()) { switch(getPlayerState()) {
case PLAYER_STATE_STOP: case PLAYER_STATE_STOP:
state = strdup(COMMAND_STOP); state = strdup(COMMAND_STOP);
...@@ -91,16 +96,18 @@ int commandStatus(FILE * fp,int argArrayLength, char ** argArray) { ...@@ -91,16 +96,18 @@ int commandStatus(FILE * fp,int argArrayLength, char ** argArray) {
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_VOLUME,getVolumeLevel()); myfprintf(fp,"%s: %i\n",COMMAND_STATUS_VOLUME,getVolumeLevel());
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_REPEAT,getPlaylistRepeatStatus()); myfprintf(fp,"%s: %i\n",COMMAND_STATUS_REPEAT,getPlaylistRepeatStatus());
myfprintf(fp,"%s: %li\n",COMMAND_STATUS_PLAYLIST,playlist.version); myfprintf(fp,"%s: %i\n",COMMAND_STATUS_RANDOM,getPlaylistRandomStatus());
myfprintf(fp,"%s: %li\n",COMMAND_STATUS_PLAYLIST,getPlaylistVersion());
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_PLAYLIST_LENGTH,getPlaylistLength());
myfprintf(fp,"%s: %s\n",COMMAND_STATUS_STATE,state); myfprintf(fp,"%s: %s\n",COMMAND_STATUS_STATE,state);
if(getPlayerState()>0) { if(getPlayerState()!=PLAYER_STATE_STOP) {
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,playlist.current); myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,getPlaylistCurrentSong());
myfprintf(fp,"%s: %i:%i\n",COMMAND_STATUS_TIME,getPlayerElapsedTime(),getPlayerTotalTime()); myfprintf(fp,"%s: %i:%i\n",COMMAND_STATUS_TIME,getPlayerElapsedTime(),getPlayerTotalTime());
} }
if(strlen(getPlayerError())) { if(getPlayerError()!=PLAYER_ERROR_NOERROR) {
myfprintf(fp,"%s: %s\n",COMMAND_STATUS_ERROR,getPlayerError()); myfprintf(fp,"%s: %s\n",COMMAND_STATUS_ERROR,getPlayerErrorStr());
} }
free(state); free(state);
...@@ -114,7 +121,7 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -114,7 +121,7 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
if(0==strcmp(argArray[0],COMMAND_PLAY)) { if(0==strcmp(argArray[0],COMMAND_PLAY)) {
int song = 0; int song = -1;
char * test; char * test;
if(argArrayLength>2) { if(argArrayLength>2) {
myfprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); myfprintf(fp,"%s too many arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
...@@ -127,7 +134,7 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -127,7 +134,7 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
return -1; return -1;
} }
} }
return playPlaylist(fp,song); return playPlaylist(fp,song,1);
} }
else if(0==strcmp(argArray[0],COMMAND_STOP)) { else if(0==strcmp(argArray[0],COMMAND_STOP)) {
if(argArrayLength!=1) { if(argArrayLength!=1) {
...@@ -160,42 +167,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -160,42 +167,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
return addToPlaylist(fp,argArray[1]); return addToPlaylist(fp,argArray[1]);
} }
else if(0==strcmp(argArray[0],COMMAND_SAVE)) { else if(0==strcmp(argArray[0],COMMAND_SAVE)) {
char * file;
int ret;
if(argArrayLength!=2) { if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1; return -1;
} }
if(strstr(argArray[1],"/")) { return savePlaylist(fp,argArray[1]);
myfprintf(fp,"%s \"%s\" contains \"/\"\n",COMMAND_RESPOND_ERROR,argArray[1]);
return -1;
}
file = malloc(strlen(playlistDir)+strlen(argArray[1])+strlen(PLAYLIST_FILE_SUFFIX)+2);
strcpy(file,playlistDir);
strcat(file,argArray[1]);
strcat(file,".");
ret = savePlaylist(fp,strcat(file,PLAYLIST_FILE_SUFFIX));
free(file);
return ret;
} }
else if(0==strcmp(argArray[0],COMMAND_RM)) { else if(0==strcmp(argArray[0],COMMAND_RM)) {
char * file;
int ret;
if(argArrayLength!=2) { if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1; return -1;
} }
if(strstr(argArray[1],"/")) { return deletePlaylist(fp,argArray[1]);
myfprintf(fp,"%s \"%s\" contains \"/\"\n",COMMAND_RESPOND_ERROR,argArray[1]);
return -1;
}
file = malloc(strlen(playlistDir)+strlen(argArray[1])+strlen(PLAYLIST_FILE_SUFFIX)+2);
strcpy(file,playlistDir);
strcat(file,argArray[1]);
strcat(file,".");
ret = deletePlaylist(fp,strcat(file,PLAYLIST_FILE_SUFFIX));
free(file);
return ret;
} }
else if(0==strcmp(argArray[0],COMMAND_DELETE)) { else if(0==strcmp(argArray[0],COMMAND_DELETE)) {
int song; int song;
...@@ -211,6 +194,72 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -211,6 +194,72 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
return deleteFromPlaylist(fp,song); return deleteFromPlaylist(fp,song);
} }
else if(0==strcmp(argArray[0],COMMAND_MOVE)) {
int from;
int to;
char * test;
if(argArrayLength!=3) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
from = strtol(argArray[1],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[1]);
return -1;
}
to = strtol(argArray[2],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[2]);
return -1;
}
return moveSongInPlaylist(fp,from,to);
}
else if(0==strcmp(argArray[0],COMMAND_SWAP)) {
int song1;
int song2;
char * test;
if(argArrayLength!=3) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
song1 = strtol(argArray[1],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[1]);
return -1;
}
song2 = strtol(argArray[2],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[2]);
return -1;
}
return swapSongsInPlaylist(fp,song1,song2);
}
else if(0==strcmp(argArray[0],COMMAND_SEEK)) {
int song;
int time;
char * test;
if(argArrayLength!=3) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
song = strtol(argArray[1],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[1]);
return -1;
}
time = strtol(argArray[2],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s \"%s\" is not a integer\n",
COMMAND_RESPOND_ERROR,argArray[2]);
return -1;
}
return seekSongInPlaylist(fp,song,time);
}
else if(0==strcmp(argArray[0],COMMAND_VOLUME)) { else if(0==strcmp(argArray[0],COMMAND_VOLUME)) {
int change; int change;
char * test; char * test;
...@@ -239,6 +288,20 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -239,6 +288,20 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
return setPlaylistRepeatStatus(fp,status); return setPlaylistRepeatStatus(fp,status);
} }
else if(0==strcmp(argArray[0],COMMAND_RANDOM)) {
int status;
char * test;
if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
status = strtol(argArray[1],&test,10);
if(*test!='\0') {
myfprintf(fp,"%s need a integer\n",COMMAND_RESPOND_ERROR);
return -1;
}
return setPlaylistRandomStatus(fp,status);
}
else if(0==strcmp(argArray[0],COMMAND_PLAYLISTINFO)) { else if(0==strcmp(argArray[0],COMMAND_PLAYLISTINFO)) {
int song = -1; int song = -1;
char * test; char * test;
...@@ -277,19 +340,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -277,19 +340,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
return clearPlaylist(fp); return clearPlaylist(fp);
} }
else if(0==strcmp(argArray[0],COMMAND_LOAD)) { else if(0==strcmp(argArray[0],COMMAND_LOAD)) {
char * file;
int ret = 0;
if(argArrayLength!=2) { if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]); myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1; return -1;
} }
file = malloc(strlen(playlistDir)+strlen(argArray[1])+strlen(PLAYLIST_FILE_SUFFIX)+2); return loadPlaylist(fp,argArray[1]);
strcpy(file,playlistDir);
strcat(file,argArray[1]);
strcat(file,".");
if(loadPlaylist(fp,strcat(file,PLAYLIST_FILE_SUFFIX))<0) ret=-1;
free(file);
return ret;
} }
else if(0==strcmp(argArray[0],COMMAND_LS)) { else if(0==strcmp(argArray[0],COMMAND_LS)) {
if(argArrayLength>2) { if(argArrayLength>2) {
...@@ -298,10 +353,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -298,10 +353,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
if(argArrayLength==1) { if(argArrayLength==1) {
if(ls(fp,NULL)<0) return -1; if(ls(fp,NULL)<0) return -1;
else return lsPlaylists(fp); else return lsPlaylists(fp,"");
} }
else { else {
return ls(fp,argArray[1]); if(ls(fp,argArray[1])<0) return -1;
else return lsPlaylists(fp,argArray[1]);
} }
} }
else if(0==strcmp(argArray[0],COMMAND_LSINFO)) { else if(0==strcmp(argArray[0],COMMAND_LSINFO)) {
...@@ -311,10 +367,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) { ...@@ -311,10 +367,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
} }
if(argArrayLength==1) { if(argArrayLength==1) {
if(printDirectoryInfo(fp,NULL)<0) return -1; if(printDirectoryInfo(fp,NULL)<0) return -1;
else return lsPlaylists(fp); else return lsPlaylists(fp,"");
} }
else { else {
return printDirectoryInfo(fp,argArray[1]); if(printDirectoryInfo(fp,argArray[1])<0) return -1;
else return lsPlaylists(fp,argArray[1]);
} }
} }
else if(0==strcmp(argArray[0],COMMAND_FIND)) { else if(0==strcmp(argArray[0],COMMAND_FIND)) {
......
...@@ -18,9 +18,12 @@ ...@@ -18,9 +18,12 @@
#include "conf.h" #include "conf.h"
#include "log.h"
#include "utils.h" #include "utils.h"
#include "buffer2array.h" #include "buffer2array.h"
#include "audio.h" #include "audio.h"
#include "volume.h"
#include <sys/param.h> #include <sys/param.h>
#include <stdio.h> #include <stdio.h>
...@@ -31,22 +34,35 @@ ...@@ -31,22 +34,35 @@
#define CONF_COMMENT '#' #define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 17 #define CONF_NUMBER_OF_PARAMS 21
#define CONF_NUMBER_OF_PATHS 4 #define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5 #define CONF_NUMBER_OF_REQUIRED 5
#define CONF_CONNECTION_TIMEOUT_DEFAULT "60" #define CONF_CONNECTION_TIMEOUT_DEFAULT "60"
#define CONF_MIXER_DEVICE_DEFAULT "/dev/mixer"
#define CONF_MAX_CONNECTIONS_DEFAULT "5" #define CONF_MAX_CONNECTIONS_DEFAULT "5"
#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "4096" #define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "4096"
#define CONF_BUFFER_BEFORE_PLAY_DEFAULT "25%" #define CONF_BUFFER_BEFORE_PLAY_DEFAULT "25%"
#define CONF_STOP_ON_ERROR_DEFAULT "yes"
#define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT "2048" #define CONF_MAX_COMMAND_LIST_SIZE_DEFAULT "2048"
#define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT "2048" #define CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT "2048"
#define CONF_AO_DRIVER_DEFAULT AUDIO_AO_DRIVER_DEFAULT #define CONF_AO_DRIVER_DEFAULT AUDIO_AO_DRIVER_DEFAULT
#define CONF_AO_DRIVER_OPTIONS_DEFAULT "" #define CONF_AO_DRIVER_OPTIONS_DEFAULT ""
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT "no" #define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT "no"
#define CONF_BIND_TO_ADDRESS_DEFAULT "any" #define CONF_BIND_TO_ADDRESS_DEFAULT "any"
#define CONF_USER_DEFAULT ""
#define CONF_LOG_LEVEL_DEFAULT "default"
#ifndef NO_OSS_MIXER
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_OSS
#define CONF_MIXER_DEVICE_DEFAULT ""
#else
#ifdef HAVE_ALSA
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_ALSA
#define CONF_MIXER_DEVICE_DEFAULT ""
#else
#define CONF_MIXER_TYPE_DEFAULT VOLUME_MIXER_NULL
#define CONF_MIXER_DEVICE_DEFAULT ""
#endif
#endif
char * conf_strings[CONF_NUMBER_OF_PARAMS] = { char * conf_strings[CONF_NUMBER_OF_PARAMS] = {
"port", "port",
...@@ -59,20 +75,26 @@ char * conf_strings[CONF_NUMBER_OF_PARAMS] = { ...@@ -59,20 +75,26 @@ char * conf_strings[CONF_NUMBER_OF_PARAMS] = {
"max_connections", "max_connections",
"max_playlist_length", "max_playlist_length",
"buffer_before_play", "buffer_before_play",
"stop_on_error",
"max_command_list_size", "max_command_list_size",
"max_output_buffer_size", "max_output_buffer_size",
"ao_driver", "ao_driver",
"ao_driver_options", "ao_driver_options",
"save_absolute_paths_in_playlists", "save_absolute_paths_in_playlists",
"bind_to_address" "bind_to_address",
"mixer_type",
"state_file",
"user",
"db_file",
"log_level"
}; };
int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = { int conf_absolutePaths[CONF_NUMBER_OF_PATHS] = {
CONF_MUSIC_DIRECTORY, CONF_MUSIC_DIRECTORY,
CONF_PLAYLIST_DIRECTORY, CONF_PLAYLIST_DIRECTORY,
CONF_LOG_FILE, CONF_LOG_FILE,
CONF_ERROR_FILE CONF_ERROR_FILE,
CONF_STATE_FILE,
CONF_DB_FILE
}; };
int conf_required[CONF_NUMBER_OF_REQUIRED] = { int conf_required[CONF_NUMBER_OF_REQUIRED] = {
...@@ -96,13 +118,15 @@ void initConf() { ...@@ -96,13 +118,15 @@ void initConf() {
conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT); conf_params[CONF_MAX_CONNECTIONS] = strdup(CONF_MAX_CONNECTIONS_DEFAULT);
conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT); conf_params[CONF_MAX_PLAYLIST_LENGTH] = strdup(CONF_MAX_PLAYLIST_LENGTH_DEFAULT);
conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT); conf_params[CONF_BUFFER_BEFORE_PLAY] = strdup(CONF_BUFFER_BEFORE_PLAY_DEFAULT);
conf_params[CONF_STOP_ON_ERROR] = strdup(CONF_STOP_ON_ERROR_DEFAULT);
conf_params[CONF_MAX_COMMAND_LIST_SIZE] = strdup(CONF_MAX_COMMAND_LIST_SIZE_DEFAULT); conf_params[CONF_MAX_COMMAND_LIST_SIZE] = strdup(CONF_MAX_COMMAND_LIST_SIZE_DEFAULT);
conf_params[CONF_MAX_OUTPUT_BUFFER_SIZE] = strdup(CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT); conf_params[CONF_MAX_OUTPUT_BUFFER_SIZE] = strdup(CONF_MAX_OUTPUT_BUFFER_SIZE_DEFAULT);
conf_params[CONF_AO_DRIVER] = strdup(CONF_AO_DRIVER_DEFAULT); conf_params[CONF_AO_DRIVER] = strdup(CONF_AO_DRIVER_DEFAULT);
conf_params[CONF_AO_DRIVER_OPTIONS] = strdup(CONF_AO_DRIVER_OPTIONS_DEFAULT); conf_params[CONF_AO_DRIVER_OPTIONS] = strdup(CONF_AO_DRIVER_OPTIONS_DEFAULT);
conf_params[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS] = strdup(CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT); conf_params[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS] = strdup(CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT);
conf_params[CONF_BIND_TO_ADDRESS] = strdup(CONF_BIND_TO_ADDRESS_DEFAULT); conf_params[CONF_BIND_TO_ADDRESS] = strdup(CONF_BIND_TO_ADDRESS_DEFAULT);
conf_params[CONF_MIXER_TYPE] = strdup(CONF_MIXER_TYPE_DEFAULT);
conf_params[CONF_USER] = strdup(CONF_USER_DEFAULT);
conf_params[CONF_LOG_LEVEL] = strdup(CONF_LOG_LEVEL_DEFAULT);
} }
char ** readConf(char * file) { char ** readConf(char * file) {
...@@ -113,7 +137,7 @@ char ** readConf(char * file) { ...@@ -113,7 +137,7 @@ char ** readConf(char * file) {
int numberOfArgs; int numberOfArgs;
if(!(fp=fopen(file,"r"))) { if(!(fp=fopen(file,"r"))) {
fprintf(stderr,"problems opening file %s for reading\n",file); ERROR1("problems opening file %s for reading\n",file);
exit(-1); exit(-1);
} }
...@@ -122,13 +146,13 @@ char ** readConf(char * file) { ...@@ -122,13 +146,13 @@ char ** readConf(char * file) {
numberOfArgs = buffer2array(string,&array); numberOfArgs = buffer2array(string,&array);
if(numberOfArgs==0) continue; if(numberOfArgs==0) continue;
if(2!=numberOfArgs) { if(2!=numberOfArgs) {
fprintf(stderr,"need two args in conf at: %s\n",string); ERROR1("need two args in conf at: %s\n",string);
exit(-1); exit(-1);
} }
i = 0; i = 0;
while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++; while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++;
if(i>=CONF_NUMBER_OF_PARAMS) { if(i>=CONF_NUMBER_OF_PARAMS) {
fprintf(stderr,"unrecognized line in conf: %s\n",string); ERROR1("unrecognized line in conf: %s\n",string);
exit(-1); exit(-1);
} }
if(conf_params[i]!=NULL) { if(conf_params[i]!=NULL) {
...@@ -144,14 +168,17 @@ char ** readConf(char * file) { ...@@ -144,14 +168,17 @@ char ** readConf(char * file) {
for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) { for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) {
if(conf_params[conf_required[i]] == NULL) { if(conf_params[conf_required[i]] == NULL) {
fprintf(stderr,"%s is unassinged in conf file\n",conf_strings[conf_required[i]]); ERROR1("%s is unassigned in conf file\n",
conf_strings[conf_required[i]]);
exit(-1); exit(-1);
} }
} }
for(i=0;i<CONF_NUMBER_OF_PATHS;i++) { for(i=0;i<CONF_NUMBER_OF_PATHS;i++) {
if(conf_params[conf_absolutePaths[i]][0]!='/') { if(conf_params[conf_absolutePaths[i]] &&
fprintf(stderr,"\"%s\" is not an absolute path\n",conf_params[conf_absolutePaths[i]]); conf_params[conf_absolutePaths[i]][0]!='/') {
ERROR1("\"%s\" is not an absolute path\n",
conf_params[conf_absolutePaths[i]]);
exit(-1); exit(-1);
} }
} }
...@@ -168,12 +195,12 @@ void writeConf(char * file) { ...@@ -168,12 +195,12 @@ void writeConf(char * file) {
FILE * fp; FILE * fp;
if(!(fp=fopen(file,"w"))) { if(!(fp=fopen(file,"w"))) {
fprintf(stderr, "problems open file %s for writing\n",file); ERROR1("problems open file %s for writing\n",file);
exit(-1); exit(-1);
} }
for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) { for(i=0;i<CONF_NUMBER_OF_PARAMS;i++) {
fprintf(fp,"%s \"%s\"\n",conf_strings[i],conf_params[i]); myfprintf(fp,"%s \"%s\"\n",conf_strings[i],conf_params[i]);
} }
fclose(fp); fclose(fp);
......
...@@ -29,13 +29,17 @@ ...@@ -29,13 +29,17 @@
#define CONF_MAX_CONNECTIONS 7 #define CONF_MAX_CONNECTIONS 7
#define CONF_MAX_PLAYLIST_LENGTH 8 #define CONF_MAX_PLAYLIST_LENGTH 8
#define CONF_BUFFER_BEFORE_PLAY 9 #define CONF_BUFFER_BEFORE_PLAY 9
#define CONF_STOP_ON_ERROR 10 #define CONF_MAX_COMMAND_LIST_SIZE 10
#define CONF_MAX_COMMAND_LIST_SIZE 11 #define CONF_MAX_OUTPUT_BUFFER_SIZE 11
#define CONF_MAX_OUTPUT_BUFFER_SIZE 12 #define CONF_AO_DRIVER 12
#define CONF_AO_DRIVER 13 #define CONF_AO_DRIVER_OPTIONS 13
#define CONF_AO_DRIVER_OPTIONS 14 #define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 14
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 15 #define CONF_BIND_TO_ADDRESS 15
#define CONF_BIND_TO_ADDRESS 16 #define CONF_MIXER_TYPE 16
#define CONF_STATE_FILE 17
#define CONF_USER 18
#define CONF_DB_FILE 19
#define CONF_LOG_LEVEL 20
/* do not free the return value, it is a static variable */ /* do not free the return value, it is a static variable */
char ** readConf(char * file); char ** readConf(char * file);
......
/* the Music Player Daemon (MPD)
* (c)2003 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 "decode.h"
#include "player.h"
#include "utils.h"
#include "audio.h"
#ifdef HAVE_MAD
#include "mp3_decode.h"
#endif
#ifdef HAVE_OGG
#include "ogg_decode.h"
#endif
#ifdef HAVE_FLAC
#include "flac_decode.h"
#endif
#include "path.h"
#include "log.h"
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/wait.h>
#include <unistd.h>
#include <string.h>
int decode_pid = 0;
void decodeSigHandler(int sig) {
if(sig==SIGCHLD) {
int status;
if(decode_pid==wait3(&status,WNOHANG,NULL)) {
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) {
ERROR1("decode process died from a "
"non-TERM signal: %i\n",
WTERMSIG(status));
}
decode_pid = 0;
}
}
else if(sig==SIGTERM) {
int pid = decode_pid;
if(pid>0) kill(pid,SIGTERM);
exit(0);
}
}
void stopDecode(DecoderControl * dc) {
if(decode_pid>0 && (dc->start || dc->state==DECODE_STATE_DECODE)) {
dc->stop = 1;
while(decode_pid>0 && dc->stop) usleep(10);
}
}
void quitDecode(PlayerControl * pc, DecoderControl * dc) {
stopDecode(dc);
pc->state = PLAYER_STATE_STOP;
pc->play = 0;
pc->stop = 0;
pc->pause = 0;
kill(getppid(),SIGUSR1);
}
int waitOnDecode(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
Buffer * cb)
{
while(decode_pid>0 && dc->start) usleep(10);
if(dc->start || dc->error!=DECODE_ERROR_NOERROR) {
strcpy(pc->erroredFile,pc->file);
pc->error = PLAYER_ERROR_FILE;
quitDecode(pc,dc);
return -1;
}
if(initAudio(af)<0) {
strcpy(pc->erroredFile,pc->file);
pc->error = PLAYER_ERROR_AUDIO;
quitDecode(pc,dc);
return -1;
}
pc->elapsedTime = 0;
pc->totalTime = cb->totalTime;
return 0;
}
void decodeSeek(PlayerControl * pc, AudioFormat * af, DecoderControl * dc,
Buffer * cb)
{
if(decode_pid>0) {
cb->next = -1;
if(dc->state!=DECODE_STATE_DECODE || dc->error ||
strcmp(dc->file,pc->file)!=0)
{
stopDecode(dc);
cb->end = 0;
dc->error = 0;
dc->start = 1;
dc->error = 0;
waitOnDecode(pc,af,dc,cb);
}
if(decode_pid>0 && dc->state==DECODE_STATE_DECODE) {
dc->seekWhere = pc->seekWhere > pc->totalTime-1 ?
pc->totalTime-1 : pc->seekWhere;
dc->seekWhere = 1 > dc->seekWhere ? 1 : dc->seekWhere;
cb->begin = 0;
dc->seek = 1;
pc->elapsedTime = dc->seekWhere;
while(decode_pid>0 && dc->seek) usleep(10);
}
}
pc->seek = 0;
}
#define processDecodeInput() \
if(pc->lockQueue) { \
pc->queueLockState = PLAYER_QUEUE_LOCKED; \
pc->lockQueue = 0; \
} \
if(pc->unlockQueue) { \
pc->queueLockState = PLAYER_QUEUE_UNLOCKED; \
pc->unlockQueue = 0; \
} \
if(pc->pause) { \
pause = !pause; \
if(pause) pc->state = PLAYER_STATE_PAUSE; \
else pc->state = PLAYER_STATE_PLAY; \
pc->pause = 0; \
kill(getppid(),SIGUSR1); \
} \
if(pc->seek) { \
decodeSeek(pc,af,dc,cb); \
bbp = 0; \
} \
if(pc->stop) { \
quitDecode(pc,dc); \
return; \
}
int decoderInit(PlayerControl * pc, Buffer * cb, AudioFormat *af,
DecoderControl * dc) {
decode_pid = fork();
if(decode_pid==0) {
/* CHILD */
while(1) {
if(dc->start) {
strcpy(dc->file,pc->file);
switch(pc->decodeType) {
#ifdef HAVE_MAD
case DECODE_TYPE_MP3:
dc->error = mp3_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_OGG
case DECODE_TYPE_OGG:
dc->error = ogg_decode(cb,af,dc);
break;
#endif
#ifdef HAVE_FLAC
case DECODE_TYPE_FLAC:
dc->error = flac_decode(cb,af,dc);
break;
#endif
default:
dc->error = DECODE_ERROR_UNKTYPE;
}
if(dc->error!=DECODE_ERROR_NOERROR) {
dc->start = 0;
dc->stop = 0;
dc->state = DECODE_STATE_STOP;
}
}
else if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else if(dc->seek) dc->start = 1;
else usleep(10);
}
exit(0);
/* END OF CHILD */
}
else if(decode_pid<0) {
strcpy(pc->erroredFile,pc->file);
pc->error = PLAYER_ERROR_SYSTEM;
return -1;
}
return 0;
}
/* decode w/ buffering
* this will fork another process
* child process does decoding
* parent process does playing audio
*/
void decode() {
Buffer * cb;
PlayerControl * pc;
AudioFormat * af;
DecoderControl * dc;
cb = &(getPlayerData()->buffer);
cb->begin = 0;
cb->end = 0;
cb->wrap = 0;
pc = &(getPlayerData()->playerControl);
dc = &(getPlayerData()->decoderControl);
af = &(getPlayerData()->audioFormat);
dc->error = 0;
dc->start = 1;
cb->next = -1;
if(decode_pid<=0) {
if(decoderInit(pc,cb,af,dc)<0) return;
}
{
/* PARENT */
char silence[CHUNK_SIZE];
int pause = 0;
int quit = 0;
int bbp = buffered_before_play;
memset(silence,0,CHUNK_SIZE);
if(waitOnDecode(pc,af,dc,cb)<0) return;
pc->state = PLAYER_STATE_PLAY;
pc->play = 0;
kill(getppid(),SIGUSR1);
while(decode_pid>0 && !cb->wrap && cb->end-cb->begin<bbp &&
dc->state==DECODE_STATE_DECODE)
{
processDecodeInput();
if(quit) return;
usleep(100);
}
while(!quit) {
processDecodeInput();
if(dc->state==DECODE_STATE_STOP &&
pc->queueState==PLAYER_QUEUE_FULL &&
pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
{
cb->next = cb->end;
dc->start = 1;
pc->queueState = PLAYER_QUEUE_DECODE;
kill(getppid(),SIGUSR1);
}
if(pause) {
playAudio(silence,CHUNK_SIZE);
}
else if((cb->begin!=cb->end || cb->wrap) &&
cb->begin!=cb->next)
{
pc->elapsedTime = cb->times[cb->begin];
playAudio(cb->chunks[cb->begin],
cb->chunkSize[cb->begin]);
cb->begin++;
if(cb->begin>=BUFFERED_CHUNKS) {
cb->begin = 0;
cb->wrap = 0;
}
}
else if(cb->next==cb->begin) {
while(pc->queueState==PLAYER_QUEUE_DECODE ||
pc->queueLockState==PLAYER_QUEUE_LOCKED)
{
processDecodeInput();
if(quit) {
quitDecode(pc,dc);
return;
}
usleep(10);
}
if(pc->queueState!=PLAYER_QUEUE_PLAY) {
quit = 1;
break;
}
else {
cb->next = -1;
if(waitOnDecode(pc,af,dc,cb)<0) return;
pc->queueState = PLAYER_QUEUE_EMPTY;
kill(getppid(),SIGUSR1);
}
}
else if(decode_pid<=0 ||
(dc->state==DECODE_STATE_STOP && !dc->start))
{
quit = 1;
break;
}
else usleep(10);
}
quitDecode(pc,dc);
/* END OF PARENT */
}
return;
}
/* the Music Player Daemon (MPD)
* (c)2003 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 DECODE_H
#define DECODE_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_STATE_STOP 0
#define DECODE_STATE_DECODE 1
#define DECODE_ERROR_NOERROR 0
#define DECODE_ERROR_UNKTYPE 1
typedef struct _DecoderControl {
int state;
int stop;
int start;
int error;
int seek;
double seekWhere;
char file[MAXPATHLEN+1];
} DecoderControl;
void decodeSigHandler(int sig);
void decode();
#endif
...@@ -23,7 +23,7 @@ ...@@ -23,7 +23,7 @@
#include "tables.h" #include "tables.h"
#include "utils.h" #include "utils.h"
#include "path.h" #include "path.h"
#include "myfprintf.h" #include "log.h"
#include "playlist.h" #include "playlist.h"
#include <string.h> #include <string.h>
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#include <dirent.h> #include <dirent.h>
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <errno.h>
#define DIRECTORY_DIR "directory: " #define DIRECTORY_DIR "directory: "
#define DIRECTORY_MTIME "mtime: " #define DIRECTORY_MTIME "mtime: "
...@@ -66,7 +67,7 @@ int updateDirectory(Directory * directory); ...@@ -66,7 +67,7 @@ int updateDirectory(Directory * directory);
int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name); int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name);
Directory * newDirectory(Directory * parentDirectory, char * dirname) { Directory * newDirectory(Directory * parentDirectory, char * dirname, time_t mtime) {
Directory * directory; Directory * directory;
directory = malloc(sizeof(Directory)); directory = malloc(sizeof(Directory));
...@@ -76,8 +77,8 @@ Directory * newDirectory(Directory * parentDirectory, char * dirname) { ...@@ -76,8 +77,8 @@ Directory * newDirectory(Directory * parentDirectory, char * dirname) {
directory->parentDirectory = parentDirectory; directory->parentDirectory = parentDirectory;
directory->subDirectories = newDirectoryList(); directory->subDirectories = newDirectoryList();
directory->songs = newSongList(); directory->songs = newSongList();
if(dirname!=NULL) directory->mtime = isDir(dirname); if(mtime<0) directory->mtime = isDir(dirname);
else directory->mtime = 0; else directory->mtime = mtime;
return directory; return directory;
} }
...@@ -116,7 +117,7 @@ int updateInDirectory(Directory * directory, char * shortname, char * name) { ...@@ -116,7 +117,7 @@ int updateInDirectory(Directory * directory, char * shortname, char * name) {
if((mtime = isMusic(name))) { if((mtime = isMusic(name))) {
if(0==findInList(directory->songs,shortname,&song)) { if(0==findInList(directory->songs,shortname,&song)) {
printf("adding %s\n",name); LOG1("adding %s\n",name);
addToDirectory(directory,shortname,name); addToDirectory(directory,shortname,name);
} }
else if(mtime>((Song *)song)->mtime) { else if(mtime>((Song *)song)->mtime) {
...@@ -243,7 +244,7 @@ int exploreDirectory(Directory * directory) { ...@@ -243,7 +244,7 @@ int exploreDirectory(Directory * directory) {
if((dir = opendir(rmp2amp(dirname)))==NULL) return -1; if((dir = opendir(rmp2amp(dirname)))==NULL) return -1;
printf("explore: %s\n",dirname); LOG1("explore: %s\n",dirname);
while((ent = readdir(dir))) { while((ent = readdir(dir))) {
if(ent->d_name[0]=='.') continue; /* hide hidden stuff */ if(ent->d_name[0]=='.') continue; /* hide hidden stuff */
if(directory->name) { if(directory->name) {
...@@ -261,7 +262,7 @@ int exploreDirectory(Directory * directory) { ...@@ -261,7 +262,7 @@ int exploreDirectory(Directory * directory) {
} }
int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name) { int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name) {
Directory * subDirectory = newDirectory(directory,name); Directory * subDirectory = newDirectory(directory,name,-1);
insertInList(directory->subDirectories,shortname,subDirectory); insertInList(directory->subDirectories,shortname,subDirectory);
exploreDirectory(subDirectory); exploreDirectory(subDirectory);
...@@ -294,6 +295,10 @@ Directory * findSubDirectory(Directory * directory,char * name) { ...@@ -294,6 +295,10 @@ Directory * findSubDirectory(Directory * directory,char * name) {
char * key; char * key;
key = strtok(dup,"/"); key = strtok(dup,"/");
if(!key) {
free(dup);
return NULL;
}
if(findInList(directory->subDirectories,key,&subDirectory)) { if(findInList(directory->subDirectories,key,&subDirectory)) {
free(dup); free(dup);
...@@ -338,7 +343,7 @@ int printDirectoryList(FILE * fp, DirectoryList * directoryList) { ...@@ -338,7 +343,7 @@ int printDirectoryList(FILE * fp, DirectoryList * directoryList) {
return 0; return 0;
} }
int printDirectoryInfo(FILE * fp,char * name) { int printDirectoryInfo(FILE * fp, char * name) {
Directory * directory; Directory * directory;
if((directory = getDirectory(name))==NULL) { if((directory = getDirectory(name))==NULL) {
...@@ -356,19 +361,19 @@ void writeDirectoryInfo(FILE * fp, Directory * directory) { ...@@ -356,19 +361,19 @@ void writeDirectoryInfo(FILE * fp, Directory * directory) {
ListNode * node = (directory->subDirectories)->firstNode; ListNode * node = (directory->subDirectories)->firstNode;
Directory * subDirectory; Directory * subDirectory;
if(directory->name) fprintf(fp,"%s%s\n",DIRECTORY_BEGIN,directory->name); if(directory->name) myfprintf(fp,"%s%s\n",DIRECTORY_BEGIN,directory->name);
while(node!=NULL) { while(node!=NULL) {
subDirectory = (Directory *)node->data; subDirectory = (Directory *)node->data;
fprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key); myfprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key);
fprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime); myfprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime);
writeDirectoryInfo(fp,subDirectory); writeDirectoryInfo(fp,subDirectory);
node = node->nextNode; node = node->nextNode;
} }
writeSongInfoFromList(fp,directory->songs); writeSongInfoFromList(fp,directory->songs);
if(directory->name) fprintf(fp,"%s%s\n",DIRECTORY_END,directory->name); if(directory->name) myfprintf(fp,"%s%s\n",DIRECTORY_END,directory->name);
} }
void readDirectoryInfo(FILE * fp,Directory * directory) { void readDirectoryInfo(FILE * fp,Directory * directory) {
...@@ -383,25 +388,25 @@ void readDirectoryInfo(FILE * fp,Directory * directory) { ...@@ -383,25 +388,25 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
if(0==strncmp(DIRECTORY_DIR,buffer,strlen(DIRECTORY_DIR))) { if(0==strncmp(DIRECTORY_DIR,buffer,strlen(DIRECTORY_DIR))) {
key = strdup(&(buffer[strlen(DIRECTORY_DIR)])); key = strdup(&(buffer[strlen(DIRECTORY_DIR)]));
if(myFgets(buffer,bufferSize,fp)<0) { if(myFgets(buffer,bufferSize,fp)<0) {
fprintf(stderr,"Error reading db\n"); ERROR0("Error reading db\n");
exit(-1); exit(-1);
} }
if(strncmp(DIRECTORY_MTIME,buffer,strlen(DIRECTORY_MTIME))) { if(strncmp(DIRECTORY_MTIME,buffer,strlen(DIRECTORY_MTIME))) {
fprintf(stderr,"Error reading db\n"); ERROR0("Error reading db\n");
printf("%s\n",buffer); ERROR1("%s\n",buffer);
exit(-1); exit(-1);
} }
mtime = atoi(&(buffer[strlen(DIRECTORY_BEGIN)])); mtime = atoi(&(buffer[strlen(DIRECTORY_BEGIN)]));
if(myFgets(buffer,bufferSize,fp)<0) { if(myFgets(buffer,bufferSize,fp)<0) {
fprintf(stderr,"Error reading db\n"); ERROR0("Error reading db\n");
exit(-1); exit(-1);
} }
if(strncmp(DIRECTORY_BEGIN,buffer,strlen(DIRECTORY_BEGIN))) { if(strncmp(DIRECTORY_BEGIN,buffer,strlen(DIRECTORY_BEGIN))) {
fprintf(stderr,"Error reading db\n"); ERROR0("Error reading db\n");
exit(-1); exit(-1);
} }
name = strdup(&(buffer[strlen(DIRECTORY_BEGIN)])); name = strdup(&(buffer[strlen(DIRECTORY_BEGIN)]));
subDirectory = newDirectory(directory,name); subDirectory = newDirectory(directory,name,mtime);
insertInList(directory->subDirectories,key,(void *)subDirectory); insertInList(directory->subDirectories,key,(void *)subDirectory);
free(key); free(key);
free(name); free(name);
...@@ -411,7 +416,7 @@ void readDirectoryInfo(FILE * fp,Directory * directory) { ...@@ -411,7 +416,7 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
readSongInfoIntoList(fp,directory->songs); readSongInfoIntoList(fp,directory->songs);
} }
else { else {
fprintf(stderr,"Unknown line in db: %s\n",buffer); ERROR1("Unknown line in db: %s\n",buffer);
exit(-1); exit(-1);
} }
} }
...@@ -436,10 +441,10 @@ int writeDirectoryDB() { ...@@ -436,10 +441,10 @@ int writeDirectoryDB() {
sortDirectory(mp3rootDirectory); sortDirectory(mp3rootDirectory);
if(!(fp=fopen(directorydb,"w"))) return -1; while(!(fp=fopen(directorydb,"w")) && errno==EINTR);
if(!fp) return -1;
writeDirectoryInfo(fp,mp3rootDirectory); writeDirectoryInfo(fp,mp3rootDirectory);
fclose(fp); while(fclose(fp) && errno==EINTR);
return 0; return 0;
} }
...@@ -447,10 +452,11 @@ int writeDirectoryDB() { ...@@ -447,10 +452,11 @@ int writeDirectoryDB() {
int readDirectoryDB() { int readDirectoryDB() {
FILE * fp; FILE * fp;
mp3rootDirectory = newDirectory(NULL,NULL); mp3rootDirectory = newDirectory(NULL,NULL,0);
if(!(fp=fopen(directorydb,"r"))) return -1; while(!(fp=fopen(directorydb,"r")) && errno==EINTR);
if(!fp) return -1;
readDirectoryInfo(fp,mp3rootDirectory); readDirectoryInfo(fp,mp3rootDirectory);
fclose(fp); while(fclose(fp) && errno==EINTR);
sortDirectory(mp3rootDirectory); sortDirectory(mp3rootDirectory);
...@@ -512,7 +518,7 @@ int printAllIn(FILE * fp, char * name) { ...@@ -512,7 +518,7 @@ int printAllIn(FILE * fp, char * name) {
} }
void initMp3Directory() { void initMp3Directory() {
mp3rootDirectory = newDirectory(NULL,NULL); mp3rootDirectory = newDirectory(NULL,NULL,0);
exploreDirectory(mp3rootDirectory); exploreDirectory(mp3rootDirectory);
sortDirectory(mp3rootDirectory); sortDirectory(mp3rootDirectory);
} }
......
...@@ -36,8 +36,6 @@ int writeDirectoryDB(); ...@@ -36,8 +36,6 @@ int writeDirectoryDB();
int readDirectoryDB(); int readDirectoryDB();
size_t getDirectoryLine(char ** buffer, int * size, FILE * fp);
int updateMp3Directory(FILE * fp); int updateMp3Directory(FILE * fp);
int printAllIn(FILE * fp, char * name); int printAllIn(FILE * fp, char * name);
......
/* the Music Player Daemon (MPD)
* (c)2003 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
*/
#ifdef HAVE_FLAC
#include "flac_decode.h"
#include "utils.h"
#include "log.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;
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.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) {
ERROR1("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)
{
ERROR1("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)) {
ERROR1("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 = 0;
cb->wrap = 0;
if(FLAC__file_decoder_seek_absolute(flacDec,
sampleToSeek))
{
data.time = ((float)sampleToSeek)/
af->sampleRate;
}
dc->seek = 0;
}
}
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:
ERROR1("flac lost sync: %s\n",data->file);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
ERROR1("bad header %s\n",data->file);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
ERROR1("crc mismatch %s\n",data->file);
break;
default:
ERROR1("unknow flac error %s\n",data->file);
}
}
void flacPrintErroredState(FLAC__FileDecoderState state, char * file) {
switch(state) {
case FLAC__FILE_DECODER_ERROR_OPENING_FILE:
ERROR1("error opening flac: %s\n",file);
break;
case FLAC__FILE_DECODER_MEMORY_ALLOCATION_ERROR:
ERROR0("flac allocation error\n");
break;
case FLAC__FILE_DECODER_SEEK_ERROR:
ERROR1("flac seek error: %s\n",file);
break;
case FLAC__FILE_DECODER_SEEKABLE_STREAM_DECODER_ERROR:
ERROR1("flac seekable stream error: %s\n",file);
break;
case FLAC__FILE_DECODER_ALREADY_INITIALIZED:
ERROR1("flac decoder already initilaized: %s\n",file);
break;
case FLAC__FILE_DECODER_INVALID_CALLBACK:
ERROR0("invalid flac callback\n");
break;
case FLAC__FILE_DECODER_UNINITIALIZED:
ERROR1("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)
{
usleep(10);
}
if(data->dc->stop) return -1;
if(data->dc->seek) return 0;
memcpy(data->cb->chunks[data->cb->end],data->chunk,CHUNK_SIZE);
data->cb->chunkSize[data->cb->end] = data->chunk_length;
data->cb->times[data->cb->end] = data->time;
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;
uint_32 samples = frame->header.blocksize;
uint_16 u16;
unsigned char * uc;
int c_samp, c_chan, d_samp;
int i;
data->time+=((float)samples)/frame->header.sample_rate;
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 flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
if(flac_getAudioFormatAndTime(dc->file,af,&(cb->totalTime))<0) {
ERROR1("\"%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
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
#ifndef FLAC_DECODE_H #ifndef FLAC_DECODE_H
#define FLAC_DECODE_H #define FLAC_DECODE_H
#include "playerData.h"
#include <stdio.h> #include <stdio.h>
int flac_decode(char * file, FILE * in, FILE * out); int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif #endif
...@@ -21,17 +21,20 @@ ...@@ -21,17 +21,20 @@
#include "command.h" #include "command.h"
#include "conf.h" #include "conf.h"
#include "list.h" #include "list.h"
#include "myfprintf.h" #include "log.h"
#include "listen.h" #include "listen.h"
#include "sig_handlers.h"
#include "playlist.h"
#include <unistd.h> #include <unistd.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <assert.h> #include <assert.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h> #include <sys/param.h>
#include <sys/select.h> #include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h> #include <string.h>
#include <fcntl.h> #include <fcntl.h>
#include <errno.h> #include <errno.h>
...@@ -59,8 +62,9 @@ typedef struct _Interface { ...@@ -59,8 +62,9 @@ typedef struct _Interface {
unsigned long long commandListSize; /* mem commandList consumes */ unsigned long long commandListSize; /* mem commandList consumes */
List * bufferList; /* for output if client is slow */ List * bufferList; /* for output if client is slow */
unsigned long long outputBufferSize; /* mem bufferList consumes */ unsigned long long outputBufferSize; /* mem bufferList consumes */
int expired; /* set wether this interface should be closed on next int expired; /* set whether this interface should be closed on next
check of old interfaces */ check of old interfaces */
int num; /* interface number */
} Interface; } Interface;
Interface * interfaces = NULL; Interface * interfaces = NULL;
...@@ -72,11 +76,12 @@ void openInterface(Interface * interface, int fd) { ...@@ -72,11 +76,12 @@ void openInterface(Interface * interface, int fd) {
assert(interface->open==0); assert(interface->open==0);
blockSignals();
interface->bufferLength = 0; interface->bufferLength = 0;
interface->fd = fd; interface->fd = fd;
fcntl(interface->fd,F_SETOWN,(int)getpid()); /* fcntl(interface->fd,F_SETOWN,(int)getpid()); */
flags = fcntl(fd,F_GETFL); flags = fcntl(fd,F_GETFL);
flags|=O_NONBLOCK | O_ASYNC; flags|=O_NONBLOCK;
fcntl(interface->fd,F_SETFL,flags); fcntl(interface->fd,F_SETFL,flags);
interface->fp = fdopen(fd,"rw"); interface->fp = fdopen(fd,"rw");
interface->open = 1; interface->open = 1;
...@@ -85,6 +90,7 @@ void openInterface(Interface * interface, int fd) { ...@@ -85,6 +90,7 @@ void openInterface(Interface * interface, int fd) {
interface->bufferList = NULL; interface->bufferList = NULL;
interface->expired = 0; interface->expired = 0;
interface->outputBufferSize = 0; interface->outputBufferSize = 0;
unblockSignals();
myfprintf(interface->fp,"%s %s %s\n",COMMAND_RESPOND_OK,GREETING,VERSION); myfprintf(interface->fp,"%s %s %s\n",COMMAND_RESPOND_OK,GREETING,VERSION);
} }
...@@ -94,46 +100,83 @@ void closeInterface(Interface * interface) { ...@@ -94,46 +100,83 @@ void closeInterface(Interface * interface) {
interface->open = 0; interface->open = 0;
if(fclose(interface->fp)) { while(fclose(interface->fp) && errno==EINTR);
fprintf(stderr,"Error closing file pointer\n");
}
if(interface->commandList) freeList(interface->commandList); if(interface->commandList) freeList(interface->commandList);
if(interface->bufferList) freeList(interface->bufferList); if(interface->bufferList) freeList(interface->bufferList);
SECURE1("interface %i: closed\n",interface->num);
} }
void openAInterface(int fd) { void openAInterface(int fd, struct sockaddr * addr) {
int i; int i;
for(i=0;i<interface_max_connections && interfaces[i].open;i++); for(i=0;i<interface_max_connections && interfaces[i].open;i++);
if(i==interface_max_connections) { if(i==interface_max_connections) {
FILE * fp = fdopen(fd,"rw"); ERROR0("Max Connections Reached!\n");
myfprintf(fp,"%s Max Connections Reached!\n",COMMAND_RESPOND_ERROR); while(close(fd) && errno==EINTR);
fclose(fp);
close(fd);
} }
else { else {
SECURE1("interface %i: opened from ",i);
switch(addr->sa_family) {
case AF_INET:
SECURE1("%s\n",inet_ntoa(
((struct sockaddr_in *)addr)->
sin_addr));
break;
#ifdef HAVE_IPV6
case AF_INET6:
{
char host[INET6_ADDRSTRLEN+1];
memset(host,0,INET6_ADDRSTRLEN+1);
SECURE1("%s\n",inet_ntop(AF_INET6,(void *)
&(((struct sockaddr_in6 *)addr)->
sin6_addr),host,INET6_ADDRSTRLEN));
}
break;
#endif
case AF_UNIX:
SECURE0("local connection\n");
break;
default:
SECURE0("unknown\n");
}
openInterface(&(interfaces[i]),fd); openInterface(&(interfaces[i]),fd);
} }
} }
int interfaceReadInput(Interface * interface) { int interfaceReadInput(Interface * interface) {
blockSignals();
if(read(interface->fd,interface->buffer+interface->bufferLength,1)>0) { if(read(interface->fd,interface->buffer+interface->bufferLength,1)>0) {
int ret = 1; int ret = 1;
int bytesRead = 1;
while(bytesRead>0) {
interface->buffer[interface->bufferLength+1] = '\0'; interface->buffer[interface->bufferLength+1] = '\0';
if(interface->buffer[interface->bufferLength]!='\r') { if(interface->buffer[interface->bufferLength]!='\r') {
interface->bufferLength++; interface->bufferLength++;
} }
if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) { if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) {
fprintf(stderr,"Buffer Overflow\n"); break;
closeInterface(interface);
} }
if(interface->buffer[interface->bufferLength-1]=='\n') { if(interface->buffer[interface->bufferLength-1]=='\n') {
break;
}
bytesRead = read(interface->fd,interface->buffer+
interface->bufferLength,1);
}
unblockSignals();
if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) {
ERROR1("interface %i: buffer overflow\n",
interface->num);
closeInterface(interface);
}
else if(interface->buffer[interface->bufferLength-1]=='\n') {
char ** argArray; char ** argArray;
int argArrayLength; int argArrayLength;
interface->buffer[interface->bufferLength-1] = '\0'; interface->buffer[interface->bufferLength-1] = '\0';
interface->bufferLength = 0;
argArrayLength = buffer2array(interface->buffer,&argArray); argArrayLength = buffer2array(interface->buffer,&argArray);
if(interface->commandList) { if(interface->commandList) {
...@@ -145,13 +188,15 @@ int interfaceReadInput(Interface * interface) { ...@@ -145,13 +188,15 @@ int interfaceReadInput(Interface * interface) {
char ** argArray; char ** argArray;
int argArrayLength; int argArrayLength;
argArrayLength = buffer2array((char *)node->data,&argArray); argArrayLength = buffer2array((char *)node->data,&argArray);
DEBUG2("interface %i: process command \"%s\"\n",interface->num,node->data);
ret = processCommand(interface->fp,argArrayLength,argArray); ret = processCommand(interface->fp,argArrayLength,argArray);
DEBUG2("interface %i: command returned %i\n",interface->num,ret);
freeArgArray(argArray,argArrayLength); freeArgArray(argArray,argArrayLength);
node = node->nextNode;
if(ret!=0 || if(ret!=0 ||
interface->expired) { interface->expired) {
break; node = NULL;
} }
node = node->nextNode;
} }
if(ret==0) { if(ret==0) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK); myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
...@@ -168,7 +213,7 @@ int interfaceReadInput(Interface * interface) { ...@@ -168,7 +213,7 @@ int interfaceReadInput(Interface * interface) {
interface->commandListSize+=sizeof(ListNode); interface->commandListSize+=sizeof(ListNode);
interface->commandListSize+=strlen(interface->buffer)+1; interface->commandListSize+=strlen(interface->buffer)+1;
if(interface->commandListSize>interface_max_command_list_size) { if(interface->commandListSize>interface_max_command_list_size) {
fprintf(stderr,"command list size (%lli) is larger than the max (%lli)\n",interface->commandListSize,interface_max_command_list_size); ERROR3("interface %i: command list size (%lli) is larger than the max (%lli)\n",interface->num,interface->commandListSize,interface_max_command_list_size);
closeInterface(interface); closeInterface(interface);
} }
...@@ -189,7 +234,11 @@ int interfaceReadInput(Interface * interface) { ...@@ -189,7 +234,11 @@ int interfaceReadInput(Interface * interface) {
myfprintf(interface->fp,"%s not in command list mode\n",COMMAND_RESPOND_ERROR); myfprintf(interface->fp,"%s not in command list mode\n",COMMAND_RESPOND_ERROR);
ret = -1; ret = -1;
} }
else ret = processCommand(interface->fp,argArrayLength,argArray); else {
DEBUG2("interface %i: process command \"%s\"\n",interface->num,interface->buffer);
ret = processCommand(interface->fp,argArrayLength,argArray);
DEBUG2("interface %i: command returned %i\n",interface->num,ret);
}
if(ret==0) { if(ret==0) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK); myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
} }
...@@ -200,11 +249,13 @@ int interfaceReadInput(Interface * interface) { ...@@ -200,11 +249,13 @@ int interfaceReadInput(Interface * interface) {
} }
} }
freeArgArray(argArray,argArrayLength); freeArgArray(argArray,argArrayLength);
interface->bufferLength = 0;
} }
return ret; return ret;
} }
else closeInterface(interface); else {
unblockSignals();
closeInterface(interface);
}
return 1; return 1;
} }
...@@ -270,7 +321,8 @@ int doIOForInterfaces() { ...@@ -270,7 +321,8 @@ int doIOForInterfaces() {
while((selret = select(FD_SETSIZE,&rfds,&wfds,NULL,&tv))) { while((selret = select(FD_SETSIZE,&rfds,&wfds,NULL,&tv))) {
if(FD_ISSET(listenSocket,&rfds)) getConnections(listenSocket); if(FD_ISSET(listenSocket,&rfds)) getConnections(listenSocket);
if(selret<0) { if(selret<0 && errno==EINTR) break;
else if(selret<0) {
closeNextErroredInterface(); closeNextErroredInterface();
continue; continue;
} }
...@@ -301,25 +353,25 @@ void initInterfaces() { ...@@ -301,25 +353,25 @@ void initInterfaces() {
interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10); interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
if(*test!='\0' || interface_timeout<=0) { if(*test!='\0' || interface_timeout<=0) {
fprintf(stderr,"connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]); ERROR1("connection timeout \"%s\" is not a positive integer\n",(getConf())[CONF_CONNECTION_TIMEOUT]);
exit(-1); exit(-1);
} }
interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10); interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10);
if(*test!='\0' || interface_max_connections<=0) { if(*test!='\0' || interface_max_connections<=0) {
fprintf(stderr,"max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]); ERROR1("max connections \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_CONNECTIONS]);
exit(-1); exit(-1);
} }
interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10); interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10);
if(*test!='\0' || interface_max_command_list_size<=0) { if(*test!='\0' || interface_max_command_list_size<=0) {
fprintf(stderr,"max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]); ERROR1("max command list size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_COMMAND_LIST_SIZE]);
exit(-1); exit(-1);
} }
interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10); interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10);
if(*test!='\0' || interface_max_output_buffer_size<=0) { if(*test!='\0' || interface_max_output_buffer_size<=0) {
fprintf(stderr,"max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]); ERROR1("max output buffer size \"%s\" is not a positive integer\n",(getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE]);
exit(-1); exit(-1);
} }
...@@ -330,6 +382,7 @@ void initInterfaces() { ...@@ -330,6 +382,7 @@ void initInterfaces() {
for(i=0;i<interface_max_connections;i++) { for(i=0;i<interface_max_connections;i++) {
interfaces[i].open = 0; interfaces[i].open = 0;
interfaces[i].num = i;
} }
} }
...@@ -356,6 +409,7 @@ void closeOldInterfaces() { ...@@ -356,6 +409,7 @@ void closeOldInterfaces() {
for(i=0;i<interface_max_connections;i++) { for(i=0;i<interface_max_connections;i++) {
if(interfaces[i].open && (interfaces[i].expired || (time(NULL)-interfaces[i].lastTime>interface_timeout))) { if(interfaces[i].open && (interfaces[i].expired || (time(NULL)-interfaces[i].lastTime>interface_timeout))) {
DEBUG1("interface %i: timeout\n",i);
closeInterface(&(interfaces[i])); closeInterface(&(interfaces[i]));
} }
} }
...@@ -374,7 +428,7 @@ void closeInterfaceWithFD(int fd) { ...@@ -374,7 +428,7 @@ void closeInterfaceWithFD(int fd) {
void flushInterfaceBuffer(Interface * interface) { void flushInterfaceBuffer(Interface * interface) {
ListNode * node = NULL; ListNode * node = NULL;
char * str; char * str;
int ret; int ret = 0;
while((node = interface->bufferList->firstNode)) { while((node = interface->bufferList->firstNode)) {
str = (char *)node->data; str = (char *)node->data;
...@@ -394,11 +448,14 @@ void flushInterfaceBuffer(Interface * interface) { ...@@ -394,11 +448,14 @@ void flushInterfaceBuffer(Interface * interface) {
} }
if(!interface->bufferList->firstNode) { if(!interface->bufferList->firstNode) {
DEBUG1("interface %i: buffer empty\n",interface->num);
freeList(interface->bufferList); freeList(interface->bufferList);
interface->bufferList = NULL; interface->bufferList = NULL;
} }
else if(errno!=EAGAIN && errno!=EINTR) { else if(ret<0 && errno!=EAGAIN && errno!=EINTR) {
/* cause interface to close */ /* cause interface to close */
DEBUG1("interface %i: problems flushing buffer\n",
interface->num);
freeList(interface->bufferList); freeList(interface->bufferList);
interface->bufferList = NULL; interface->bufferList = NULL;
interface->expired = 1; interface->expired = 1;
...@@ -415,29 +472,33 @@ void flushAllInterfaceBuffers() { ...@@ -415,29 +472,33 @@ void flushAllInterfaceBuffers() {
} }
} }
void interfacePrintWithFD(int fd,char * buffer) { int interfacePrintWithFD(int fd,char * buffer) {
int i; int i;
int ret; int ret;
if(!strlen(buffer)) return; if(!strlen(buffer)) return -1;
for(i=0;i<interface_max_connections;i++) { for(i=0;i<interface_max_connections;i++) {
if(interfaces[i].fd==fd) break; if(interfaces[i].fd==fd) break;
} }
/* if fd isn't found or interfaces is going to be closed, do nothing */ /* if fd isn't found or interfaces is going to be closed, do nothing */
if(i==interface_max_connections || interfaces[i].expired) return; if(i==interface_max_connections || interfaces[i].expired) return -1;
if(interfaces[i].bufferList) { if(interfaces[i].bufferList) {
interfaces[i].outputBufferSize+=sizeof(ListNode); interfaces[i].outputBufferSize+=sizeof(ListNode);
interfaces[i].outputBufferSize+=strlen(buffer)+1; interfaces[i].outputBufferSize+=strlen(buffer)+1;
if(interfaces[i].outputBufferSize>interface_max_output_buffer_size) { if(interfaces[i].outputBufferSize>interface_max_output_buffer_size) {
fprintf(stderr,"output buffer size (%lli) is larger than the max (%lli)\n",interfaces[i].outputBufferSize,interface_max_output_buffer_size); ERROR3("interface %i: output buffer size (%lli) is "
"larger than the max (%lli)\n",
interfaces[i].num,
interfaces[i].outputBufferSize,
interface_max_output_buffer_size);
/* cause interface to close */ /* cause interface to close */
freeList(interfaces[i].bufferList); freeList(interfaces[i].bufferList);
interfaces[i].bufferList = NULL; interfaces[i].bufferList = NULL;
interfaces[i].expired = 1; interfaces[i].expired = 1;
return; return 0;
} }
else { else {
insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer)); insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer));
...@@ -451,19 +512,23 @@ void interfacePrintWithFD(int fd,char * buffer) { ...@@ -451,19 +512,23 @@ void interfacePrintWithFD(int fd,char * buffer) {
insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer)); insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer));
} }
else { else {
DEBUG1("interface %i: problems writing\n",i);
interfaces[i].expired = 1; interfaces[i].expired = 1;
return; return 0;
} }
} }
else if(ret<strlen(buffer)) { else if(ret<strlen(buffer)) {
interfaces[i].bufferList = makeList(free); interfaces[i].bufferList = makeList(free);
insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(&buffer[ret])); insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(&buffer[ret]));
} }
/* if we needed to create buffer, initizliaze bufferSize info */ /* if we needed to create buffer, initialize bufferSize info */
if(interfaces[i].bufferList) { if(interfaces[i].bufferList) {
DEBUG1("interface %i: buffer created\n",i);
interfaces[i].outputBufferSize = sizeof(List); interfaces[i].outputBufferSize = sizeof(List);
interfaces[i].outputBufferSize+=sizeof(ListNode); interfaces[i].outputBufferSize+=sizeof(ListNode);
interfaces[i].outputBufferSize+=strlen((char *)interfaces[i].bufferList->firstNode->data)+1; interfaces[i].outputBufferSize+=strlen((char *)interfaces[i].bufferList->firstNode->data)+1;
} }
} }
return 0;
} }
...@@ -21,15 +21,17 @@ ...@@ -21,15 +21,17 @@
#include <stdio.h> #include <stdio.h>
#include <time.h> #include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
void initInterfaces(); void initInterfaces();
void openAInterface(int fd); void openAInterface(int fd, struct sockaddr * addr);
void closeAllInterfaces(); void closeAllInterfaces();
void freeAllInterfaces(); void freeAllInterfaces();
void closeOldInterfaces(); void closeOldInterfaces();
void closeInterfaceWithFD(int fd); void closeInterfaceWithFD(int fd);
void flushAllInterfaceBuffers(); void flushAllInterfaceBuffers();
void interfacePrintWithFD(int fd, char * buffer); int interfacePrintWithFD(int fd, char * buffer);
int doIOForInterfaces(); int doIOForInterfaces();
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library libid3tag - ID3 tag manipulation library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: CHANGES,v 1.2 2003/07/05 05:18:51 shank Exp $ $Id: CHANGES,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library libid3tag - ID3 tag manipulation library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: CREDITS,v 1.2 2003/07/05 05:18:51 shank Exp $ $Id: CREDITS,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
## along with this program; if not, write to the Free Software ## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
## $Id: Makefile.am,v 1.3 2003/07/05 06:12:40 shank Exp $ ## $Id: Makefile.am,v 1.1 2003/08/14 03:57:13 shank Exp $
## ##
## Process this file with automake to produce Makefile.in ## Process this file with automake to produce Makefile.in
......
...@@ -66,12 +66,19 @@ EXEEXT = @EXEEXT@ ...@@ -66,12 +66,19 @@ EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@ AS = @AS@
AWK = @AWK@ AWK = @AWK@
CC = @CC@ CC = @CC@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@ DLLTOOL = @DLLTOOL@
ECHO = @ECHO@ ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@ LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBTOOL_DEPS = @LIBTOOL_DEPS@
...@@ -79,6 +86,7 @@ LN_S = @LN_S@ ...@@ -79,6 +86,7 @@ LN_S = @LN_S@
OBJDUMP = @OBJDUMP@ OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@ STRIP = @STRIP@
VERSION = @VERSION@ VERSION = @VERSION@
am__include = @am__include@ am__include = @am__include@
...@@ -123,7 +131,7 @@ libid3tag_la_LDFLAGS = -version-info $(version_info) ...@@ -123,7 +131,7 @@ libid3tag_la_LDFLAGS = -version-info $(version_info)
BUILT_SOURCES = frametype.c compat.c genre.dat BUILT_SOURCES = frametype.c compat.c genre.dat
subdir = . subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs
CONFIG_HEADER = config.h CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = libid3tag.list CONFIG_CLEAN_FILES = libid3tag.list
LTLIBRARIES = $(noinst_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES)
...@@ -141,7 +149,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I. ...@@ -141,7 +149,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
CPPFLAGS = @CPPFLAGS@ CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/../depcomp depcomp = $(SHELL) $(top_srcdir)/../../depcomp
am__depfiles_maybe = depfiles am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/compat.Plo ./$(DEPDIR)/crc.Plo \ @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/compat.Plo ./$(DEPDIR)/crc.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/debug.Plo ./$(DEPDIR)/field.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/debug.Plo ./$(DEPDIR)/field.Plo \
...@@ -168,10 +176,11 @@ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ ...@@ -168,10 +176,11 @@ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
uninstall-info-recursive all-recursive install-data-recursive \ uninstall-info-recursive all-recursive install-data-recursive \
install-exec-recursive installdirs-recursive install-recursive \ install-exec-recursive installdirs-recursive install-recursive \
uninstall-recursive check-recursive installcheck-recursive uninstall-recursive check-recursive installcheck-recursive
DIST_COMMON = README $(noinst_HEADERS) ../config.guess ../config.sub \ DIST_COMMON = README $(noinst_HEADERS) ../../config.guess \
../depcomp ../install-sh ../ltmain.sh ../missing \ ../../config.sub ../../depcomp ../../install-sh ../../ltmain.sh \
../mkinstalldirs COPYING INSTALL Makefile.am Makefile.in TODO \ ../../missing ../../mkinstalldirs COPYING INSTALL Makefile.am \
aclocal.m4 config.h.in configure configure.ac libid3tag.list.in Makefile.in TODO aclocal.m4 config.h.in configure configure.ac \
libid3tag.list.in
DIST_SUBDIRS = $(SUBDIRS) DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(libid3tag_la_SOURCES) $(EXTRA_libid3tag_la_SOURCES) SOURCES = $(libid3tag_la_SOURCES) $(EXTRA_libid3tag_la_SOURCES)
...@@ -394,7 +403,7 @@ distcleancheck_listfiles = find . -type f -print ...@@ -394,7 +403,7 @@ distcleancheck_listfiles = find . -type f -print
distdir: $(DISTFILES) distdir: $(DISTFILES)
$(am__remove_distdir) $(am__remove_distdir)
mkdir $(distdir) mkdir $(distdir)
$(mkinstalldirs) $(distdir)/. $(distdir)/.. $(mkinstalldirs) $(distdir)/. $(distdir)/../..
@list='$(DISTFILES)'; for file in $$list; do \ @list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library libid3tag - ID3 tag manipulation library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: README,v 1.2 2003/07/05 05:18:51 shank Exp $ $Id: README,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library libid3tag - ID3 tag manipulation library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: TODO,v 1.2 2003/07/05 05:18:51 shank Exp $ $Id: TODO,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* C code produced by gperf version 3.0 */ /* C code produced by gperf version 3.0.1 */
/* Command-line: gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k '*' compat.gperf */ /* Command-line: gperf -tCcTonD -K id -N id3_compat_lookup -s -3 -k '*' compat.gperf */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
...@@ -48,7 +48,7 @@ error "gperf generated tables don't work with this execution character set. Plea ...@@ -48,7 +48,7 @@ error "gperf generated tables don't work with this execution character set. Plea
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Id: compat.gperf,v 1.2 2003/07/05 05:18:51 shank Exp * Id: compat.gperf,v 1.1 2003/08/14 03:57:13 shank Exp
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: compat.gperf,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: compat.gperf,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: compat.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: compat.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_COMPAT_H # ifndef LIBID3TAG_COMPAT_H
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -17,7 +17,7 @@ dnl You should have received a copy of the GNU General Public License ...@@ -17,7 +17,7 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
dnl dnl
AC_REVISION([$Id: configure.ac,v 1.3 2003/07/05 05:39:48 shank Exp $])dnl AC_REVISION([$Id: configure.ac,v 1.1 2003/08/14 03:57:13 shank Exp $])dnl
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: crc.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: crc.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: crc.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: crc.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_CRC_H # ifndef LIBID3TAG_CRC_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: debug.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: debug.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: debug.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: debug.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_DEBUG_H # ifndef LIBID3TAG_DEBUG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: field.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: field.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: field.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: field.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_FIELD_H # ifndef LIBID3TAG_FIELD_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: file.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: file.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: file.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: file.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_FILE_H # ifndef LIBID3TAG_FILE_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frame.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: frame.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frame.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: frame.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_FRAME_H # ifndef LIBID3TAG_FRAME_H
......
/* C code produced by gperf version 3.0 */ /* C code produced by gperf version 3.0.1 */
/* Command-line: gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*' frametype.gperf */ /* Command-line: gperf -tCcTonD -K id -N id3_frametype_lookup -s -3 -k '*' frametype.gperf */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \ #if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
...@@ -48,7 +48,7 @@ error "gperf generated tables don't work with this execution character set. Plea ...@@ -48,7 +48,7 @@ error "gperf generated tables don't work with this execution character set. Plea
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Id: frametype.gperf,v 1.2 2003/07/05 05:18:51 shank Exp * Id: frametype.gperf,v 1.1 2003/08/14 03:57:13 shank Exp
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frametype.gperf,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: frametype.gperf,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frametype.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: frametype.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_FRAMETYPE_H # ifndef LIBID3TAG_FRAMETYPE_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: genre.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: genre.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -17,7 +17,7 @@ ...@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* Id: genre.dat.in,v 1.2 2003/07/05 05:18:51 shank Exp * Id: genre.dat.in,v 1.1 2003/08/14 03:57:13 shank Exp
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: genre.dat.in,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: genre.dat.in,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# $Id: genre.dat.sed,v 1.2 2003/07/05 05:18:51 shank Exp $ # $Id: genre.dat.sed,v 1.1 2003/08/14 03:57:13 shank Exp $
# #
1i\ 1i\
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: genre.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: genre.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_GENRE_H # ifndef LIBID3TAG_GENRE_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: global.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: global.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_GLOBAL_H # ifndef LIBID3TAG_GLOBAL_H
......
...@@ -19,7 +19,7 @@ ...@@ -19,7 +19,7 @@
* If you would like to negotiate alternate licensing terms, you may do * If you would like to negotiate alternate licensing terms, you may do
* so by contacting: Underbit Technologies, Inc. <info@underbit.com> * so by contacting: Underbit Technologies, Inc. <info@underbit.com>
* *
* $Id: id3tag.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: id3tag.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_ID3TAG_H # ifndef LIBID3TAG_ID3TAG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: latin1.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: latin1.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: latin1.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: latin1.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_LATIN1_H # ifndef LIBID3TAG_LATIN1_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: parse.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: parse.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: parse.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: parse.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_PARSE_H # ifndef LIBID3TAG_PARSE_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: render.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: render.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: render.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: render.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_RENDER_H # ifndef LIBID3TAG_RENDER_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: tag.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: tag.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: tag.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: tag.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_TAG_H # ifndef LIBID3TAG_TAG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: ucs4.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: ucs4.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: ucs4.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: ucs4.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_UCS4_H # ifndef LIBID3TAG_UCS4_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: utf16.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: utf16.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: utf16.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: utf16.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_UTF16_H # ifndef LIBID3TAG_UTF16_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: utf8.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: utf8.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: utf8.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: utf8.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_UTF8_H # ifndef LIBID3TAG_UTF8_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: util.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: util.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: util.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: util.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_UTIL_H # ifndef LIBID3TAG_UTIL_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: version.c,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: version.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: version.h,v 1.2 2003/07/05 05:18:51 shank Exp $ * $Id: version.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBID3TAG_VERSION_H # ifndef LIBID3TAG_VERSION_H
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library libmad - MPEG audio decoder library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: CHANGES,v 1.1 2003/07/05 06:20:49 shank Exp $ $Id: CHANGES,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library libmad - MPEG audio decoder library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: CREDITS,v 1.1 2003/07/05 06:20:50 shank Exp $ $Id: CREDITS,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: D.dat,v 1.2 2003/07/05 06:20:50 shank Exp $ * $Id: D.dat,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
## along with this program; if not, write to the Free Software ## along with this program; if not, write to the Free Software
## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ## Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
## ##
## $Id: Makefile.am,v 1.3 2003/07/05 06:20:50 shank Exp $ ## $Id: Makefile.am,v 1.1 2003/08/14 03:57:13 shank Exp $
## ##
## Process this file with automake to produce Makefile.in ## Process this file with automake to produce Makefile.in
......
...@@ -66,6 +66,7 @@ EXEEXT = @EXEEXT@ ...@@ -66,6 +66,7 @@ EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@ OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@ PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@ AMTAR = @AMTAR@
AR = @AR@
AS = @AS@ AS = @AS@
ASO = @ASO@ ASO = @ASO@
ASO_OBJS = @ASO_OBJS@ ASO_OBJS = @ASO_OBJS@
...@@ -73,10 +74,16 @@ AWK = @AWK@ ...@@ -73,10 +74,16 @@ AWK = @AWK@
CC = @CC@ CC = @CC@
CCAS = @CCAS@ CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@ CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@ DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@ DLLTOOL = @DLLTOOL@
ECHO = @ECHO@ ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
FPM = @FPM@ FPM = @FPM@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@ LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@ LIBTOOL_DEPS = @LIBTOOL_DEPS@
...@@ -84,6 +91,7 @@ LN_S = @LN_S@ ...@@ -84,6 +91,7 @@ LN_S = @LN_S@
OBJDUMP = @OBJDUMP@ OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@ PACKAGE = @PACKAGE@
RANLIB = @RANLIB@ RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@ STRIP = @STRIP@
VERSION = @VERSION@ VERSION = @VERSION@
am__include = @am__include@ am__include = @am__include@
...@@ -142,7 +150,7 @@ version_info = $(version_current):$(version_revision):$(version_age) ...@@ -142,7 +150,7 @@ version_info = $(version_current):$(version_revision):$(version_age)
libmad_la_LDFLAGS = -version-info $(version_info) libmad_la_LDFLAGS = -version-info $(version_info)
subdir = . subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs
CONFIG_HEADER = config.h CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = libmad.list CONFIG_CLEAN_FILES = libmad.list
LTLIBRARIES = $(noinst_LTLIBRARIES) LTLIBRARIES = $(noinst_LTLIBRARIES)
...@@ -164,7 +172,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I. ...@@ -164,7 +172,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
CPPFLAGS = @CPPFLAGS@ CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@ LDFLAGS = @LDFLAGS@
LIBS = @LIBS@ LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/../depcomp depcomp = $(SHELL) $(top_srcdir)/../../depcomp
am__depfiles_maybe = depfiles am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bit.Plo ./$(DEPDIR)/decoder.Plo \ @AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bit.Plo ./$(DEPDIR)/decoder.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/fixed.Plo ./$(DEPDIR)/frame.Plo \ @AMDEP_TRUE@ ./$(DEPDIR)/fixed.Plo ./$(DEPDIR)/frame.Plo \
...@@ -192,10 +200,11 @@ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \ ...@@ -192,10 +200,11 @@ RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
uninstall-info-recursive all-recursive install-data-recursive \ uninstall-info-recursive all-recursive install-data-recursive \
install-exec-recursive installdirs-recursive install-recursive \ install-exec-recursive installdirs-recursive install-recursive \
uninstall-recursive check-recursive installcheck-recursive uninstall-recursive check-recursive installcheck-recursive
DIST_COMMON = README $(noinst_HEADERS) ../config.guess ../config.sub \ DIST_COMMON = README $(noinst_HEADERS) ../../config.guess \
../depcomp ../install-sh ../ltmain.sh ../missing \ ../../config.sub ../../depcomp ../../install-sh ../../ltmain.sh \
../mkinstalldirs COPYING INSTALL Makefile.am Makefile.in TODO \ ../../missing ../../mkinstalldirs COPYING INSTALL Makefile.am \
aclocal.m4 config.h.in configure configure.ac libmad.list.in Makefile.in TODO aclocal.m4 config.h.in configure configure.ac \
libmad.list.in
DIST_SUBDIRS = $(SUBDIRS) DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(libmad_la_SOURCES) $(EXTRA_libmad_la_SOURCES) $(minimad_SOURCES) SOURCES = $(libmad_la_SOURCES) $(EXTRA_libmad_la_SOURCES) $(minimad_SOURCES)
...@@ -425,7 +434,7 @@ distcleancheck_listfiles = find . -type f -print ...@@ -425,7 +434,7 @@ distcleancheck_listfiles = find . -type f -print
distdir: $(DISTFILES) distdir: $(DISTFILES)
$(am__remove_distdir) $(am__remove_distdir)
mkdir $(distdir) mkdir $(distdir)
$(mkinstalldirs) $(distdir)/. $(distdir)/.. $(mkinstalldirs) $(distdir)/. $(distdir)/../..
@list='$(DISTFILES)'; for file in $$list; do \ @list='$(DISTFILES)'; for file in $$list; do \
if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \ dir=`echo "$$file" | sed -e 's,/[^/]*$$,,'`; \
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library libmad - MPEG audio decoder library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: README,v 1.1 2003/07/05 06:20:50 shank Exp $ $Id: README,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
...@@ -2,7 +2,7 @@ ...@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library libmad - MPEG audio decoder library
Copyright (C) 2000-2003 Underbit Technologies, Inc. Copyright (C) 2000-2003 Underbit Technologies, Inc.
$Id: TODO,v 1.1 2003/07/05 06:20:50 shank Exp $ $Id: TODO,v 1.1 2003/08/14 03:57:13 shank Exp $
=============================================================================== ===============================================================================
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: bit.c,v 1.2 2003/07/05 06:20:50 shank Exp $ * $Id: bit.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: bit.h,v 1.2 2003/07/05 06:20:50 shank Exp $ * $Id: bit.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_BIT_H # ifndef LIBMAD_BIT_H
......
This source diff could not be displayed because it is too large. You can view the blob instead.
...@@ -17,7 +17,7 @@ dnl You should have received a copy of the GNU General Public License ...@@ -17,7 +17,7 @@ dnl You should have received a copy of the GNU General Public License
dnl along with this program; if not, write to the Free Software dnl along with this program; if not, write to the Free Software
dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA dnl Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
dnl dnl
AC_REVISION([$Id: configure.ac,v 1.1 2003/07/05 06:20:51 shank Exp $])dnl AC_REVISION([$Id: configure.ac,v 1.1 2003/08/14 03:57:13 shank Exp $])dnl
dnl Process this file with autoconf to produce a configure script. dnl Process this file with autoconf to produce a configure script.
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: decoder.c,v 1.2 2003/07/05 06:20:51 shank Exp $ * $Id: decoder.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: decoder.h,v 1.2 2003/07/05 06:20:51 shank Exp $ * $Id: decoder.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_DECODER_H # ifndef LIBMAD_DECODER_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: fixed.c,v 1.2 2003/07/05 06:20:51 shank Exp $ * $Id: fixed.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: fixed.h,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: fixed.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_FIXED_H # ifndef LIBMAD_FIXED_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frame.c,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: frame.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: frame.h,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: frame.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_FRAME_H # ifndef LIBMAD_FRAME_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: global.h,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: global.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_GLOBAL_H # ifndef LIBMAD_GLOBAL_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: huffman.c,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: huffman.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: huffman.h,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: huffman.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_HUFFMAN_H # ifndef LIBMAD_HUFFMAN_H
......
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
* *
***************************************************************************** *****************************************************************************
* *
* $Id: imdct_l_arm.S,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: imdct_l_arm.S,v 1.1 2003/08/14 03:57:13 shank Exp $
* *
* 2001/03/24: Andre McCurdy <armccurdy@yahoo.co.uk> * 2001/03/24: Andre McCurdy <armccurdy@yahoo.co.uk>
* - Corrected PIC unsafe loading of address of 'imdct36_long_karray' * - Corrected PIC unsafe loading of address of 'imdct36_long_karray'
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: imdct_s.dat,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: imdct_s.dat,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* 0 */ { MAD_F(0x09bd7ca0) /* 0.608761429 */, /* 0 */ { MAD_F(0x09bd7ca0) /* 0.608761429 */,
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: layer12.c,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: layer12.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: layer12.h,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: layer12.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_LAYER12_H # ifndef LIBMAD_LAYER12_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: layer3.c,v 1.2 2003/07/05 06:20:52 shank Exp $ * $Id: layer3.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: layer3.h,v 1.2 2003/07/05 06:20:53 shank Exp $ * $Id: layer3.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_LAYER3_H # ifndef LIBMAD_LAYER3_H
......
...@@ -33,7 +33,7 @@ extern "C" { ...@@ -33,7 +33,7 @@ extern "C" {
# define SIZEOF_LONG_LONG 8 # define SIZEOF_LONG_LONG 8
/* Id: version.h,v 1.2 2003/07/05 06:20:55 shank Exp */ /* Id: version.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_VERSION_H # ifndef LIBMAD_VERSION_H
# define LIBMAD_VERSION_H # define LIBMAD_VERSION_H
...@@ -62,7 +62,7 @@ extern char const mad_build[]; ...@@ -62,7 +62,7 @@ extern char const mad_build[];
# endif # endif
/* Id: fixed.h,v 1.2 2003/07/05 06:20:52 shank Exp */ /* Id: fixed.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_FIXED_H # ifndef LIBMAD_FIXED_H
# define LIBMAD_FIXED_H # define LIBMAD_FIXED_H
...@@ -528,7 +528,7 @@ mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t); ...@@ -528,7 +528,7 @@ mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
# endif # endif
/* Id: bit.h,v 1.2 2003/07/05 06:20:50 shank Exp */ /* Id: bit.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_BIT_H # ifndef LIBMAD_BIT_H
# define LIBMAD_BIT_H # define LIBMAD_BIT_H
...@@ -557,7 +557,7 @@ unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short); ...@@ -557,7 +557,7 @@ unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
# endif # endif
/* Id: timer.h,v 1.2 2003/07/05 06:20:55 shank Exp */ /* Id: timer.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_TIMER_H # ifndef LIBMAD_TIMER_H
# define LIBMAD_TIMER_H # define LIBMAD_TIMER_H
...@@ -639,7 +639,7 @@ void mad_timer_string(mad_timer_t, char *, char const *, ...@@ -639,7 +639,7 @@ void mad_timer_string(mad_timer_t, char *, char const *,
# endif # endif
/* Id: stream.h,v 1.2 2003/07/05 06:20:55 shank Exp */ /* Id: stream.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_STREAM_H # ifndef LIBMAD_STREAM_H
# define LIBMAD_STREAM_H # define LIBMAD_STREAM_H
...@@ -727,7 +727,7 @@ char const *mad_stream_errorstr(struct mad_stream const *); ...@@ -727,7 +727,7 @@ char const *mad_stream_errorstr(struct mad_stream const *);
# endif # endif
/* Id: frame.h,v 1.2 2003/07/05 06:20:52 shank Exp */ /* Id: frame.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_FRAME_H # ifndef LIBMAD_FRAME_H
# define LIBMAD_FRAME_H # define LIBMAD_FRAME_H
...@@ -824,7 +824,7 @@ void mad_frame_mute(struct mad_frame *); ...@@ -824,7 +824,7 @@ void mad_frame_mute(struct mad_frame *);
# endif # endif
/* Id: synth.h,v 1.2 2003/07/05 06:20:55 shank Exp */ /* Id: synth.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_SYNTH_H # ifndef LIBMAD_SYNTH_H
# define LIBMAD_SYNTH_H # define LIBMAD_SYNTH_H
...@@ -873,7 +873,7 @@ void mad_synth_frame(struct mad_synth *, struct mad_frame const *); ...@@ -873,7 +873,7 @@ void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
# endif # endif
/* Id: decoder.h,v 1.2 2003/07/05 06:20:51 shank Exp */ /* Id: decoder.h,v 1.1 2003/08/14 03:57:13 shank Exp */
# ifndef LIBMAD_DECODER_H # ifndef LIBMAD_DECODER_H
# define LIBMAD_DECODER_H # define LIBMAD_DECODER_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
# along with this program; if not, write to the Free Software # along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
# #
# $Id: mad.h.sed,v 1.2 2003/07/05 06:20:53 shank Exp $ # $Id: mad.h.sed,v 1.1 2003/08/14 03:57:13 shank Exp $
# #
/^\/\*$/{ /^\/\*$/{
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: minimad.c,v 1.1 2003/07/05 06:20:53 shank Exp $ * $Id: minimad.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# include <stdio.h> # include <stdio.h>
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: qc_table.dat,v 1.2 2003/07/05 06:20:53 shank Exp $ * $Id: qc_table.dat,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: rq_table.dat,v 1.2 2003/07/05 06:20:53 shank Exp $ * $Id: rq_table.dat,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: sf_table.dat,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: sf_table.dat,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
/* /*
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: stream.c,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: stream.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: stream.h,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: stream.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_STREAM_H # ifndef LIBMAD_STREAM_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: synth.c,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: synth.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: synth.h,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: synth.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_SYNTH_H # ifndef LIBMAD_SYNTH_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: timer.c,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: timer.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: timer.h,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: timer.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_TIMER_H # ifndef LIBMAD_TIMER_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: version.c,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: version.c,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifdef HAVE_CONFIG_H # ifdef HAVE_CONFIG_H
......
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software * along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
* *
* $Id: version.h,v 1.2 2003/07/05 06:20:55 shank Exp $ * $Id: version.h,v 1.1 2003/08/14 03:57:13 shank Exp $
*/ */
# ifndef LIBMAD_VERSION_H # ifndef LIBMAD_VERSION_H
......
...@@ -61,7 +61,7 @@ int insertInList(List * list,char * key,void * data) { ...@@ -61,7 +61,7 @@ int insertInList(List * list,char * key,void * data) {
assert(list!=NULL); assert(list!=NULL);
assert(key!=NULL); assert(key!=NULL);
assert(data!=NULL); /*assert(data!=NULL);*/
node = malloc(sizeof(ListNode)); node = malloc(sizeof(ListNode));
assert(node!=NULL); assert(node!=NULL);
......
...@@ -46,13 +46,13 @@ typedef struct _List { ...@@ -46,13 +46,13 @@ typedef struct _List {
ListNode * lastNode; ListNode * lastNode;
/* function used to free data stored in nodes of the list */ /* function used to free data stored in nodes of the list */
ListFreeDataFunc * freeDataFunc; ListFreeDataFunc * freeDataFunc;
/* number of ndoes */ /* number of nodes */
long numberOfNodes; long numberOfNodes;
/* array for searching when list is sorted */ /* array for searching when list is sorted */
ListNode ** nodesArray; ListNode ** nodesArray;
} List; } List;
/* allocates memmory for a new list and initializes it /* allocates memory for a new list and initializes it
* _freeDataFunc_ -> pointer to function used to free data, use * _freeDataFunc_ -> pointer to function used to free data, use
* DEFAULT_FREE_DATAFUNC to use free() * DEFAULT_FREE_DATAFUNC to use free()
* returns pointer to new list if successful, NULL otherwise * returns pointer to new list if successful, NULL otherwise
...@@ -82,12 +82,12 @@ void deleteNodeFromList(List * list,ListNode * node); ...@@ -82,12 +82,12 @@ void deleteNodeFromList(List * list,ListNode * node);
* _list_ -> list to search for _key_ in * _list_ -> list to search for _key_ in
* _key_ -> which node is being searched for * _key_ -> which node is being searched for
* _data_ -> a pointer to where data will be placed, * _data_ -> a pointer to where data will be placed,
* _data_ memmory should not by allocated or freed * _data_ memory should not by allocated or freed
* returns 1 if successful, 0 otherwise * returns 1 if successful, 0 otherwise
*/ */
int findInList(List * list, char * key, void ** data); int findInList(List * list, char * key, void ** data);
/* frees memmory malloc'd for list and its nodes /* frees memory malloc'd for list and its nodes
* _list_ -> List to be free'd * _list_ -> List to be free'd
*/ */
void freeList(void * list); void freeList(void * list);
......
/* the Music Player Daemon (MPD)
* (c)2002 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 "listen.h"
#include "interface.h"
#include "conf.h"
#include "log.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <netinet/in.h>
#include <netdb.h>
#include <string.h>
#include <errno.h>
#include <resolv.h>
#include <fcntl.h>
#define MAXHOSTNAME 1024
#define ALLOW_REUSE 1
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;
struct sockaddr * addrp;
socklen_t addrlen;
struct sockaddr_in sin;
int pf;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
memset(&sin6, 0, sizeof(struct sockaddr_in6));
sin6.sin6_port = htons(port);
sin6.sin6_family = AF_INET6;
#endif
memset(&sin, 0, sizeof(struct sockaddr_in));
sin.sin_port = htons(port);
sin.sin_family = AF_INET;
if(strcmp((getConf())[CONF_BIND_TO_ADDRESS],"any")==0) {
#ifdef HAVE_IPV6
if(ipv6Supported()) {
sin6.sin6_addr = in6addr_any;
addrp = (struct sockaddr *) &sin6;
addrlen = sizeof(struct sockaddr_in6);
}
else
#endif
{
sin.sin_addr.s_addr = INADDR_ANY;
addrp = (struct sockaddr *) &sin;
addrlen = sizeof(struct sockaddr_in);
}
}
else {
struct hostent * he;
if(!(he = gethostbyname((getConf())[CONF_BIND_TO_ADDRESS]))) {
ERROR1("can't lookup host \"%s\"\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
}
switch(he->h_addrtype) {
#ifdef HAVE_IPV6
case AF_INET6:
if(!ipv6Supported()) {
ERROR1("no IPv6 support, but a IPv6 address "
"found for \"%s\"\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
}
bcopy((char *)he->h_addr,(char *)
&sin6.sin6_addr.s6_addr,he->h_length);
addrp = (struct sockaddr *) &sin6;
addrlen = sizeof(struct sockaddr_in6);
break;
#endif
case AF_INET:
bcopy((char *)he->h_addr,(char *)&sin.sin_addr.s_addr,
he->h_length);
addrp = (struct sockaddr *) &sin;
addrlen = sizeof(struct sockaddr_in);
break;
default:
ERROR1("address type for \"%s\" is not IPv4 or IPv6\n",
(getConf())[CONF_BIND_TO_ADDRESS]);
exit(-1);
}
}
switch(addrp->sa_family) {
case AF_INET:
pf = PF_INET;
break;
#ifdef HAVE_IPV6
case AF_INET6:
pf = PF_INET6;
break;
#endif
case AF_UNIX:
pf = PF_UNIX;
break;
default:
ERROR1("unknown address family: %i\n",addrp->sa_family);
return -1;
}
if((sock = socket(addrp->sa_family,SOCK_STREAM,0)) < 0) {
ERROR0("socket < 0\n");
return -1;
}
if(setsockopt(sock,SOL_SOCKET,SO_REUSEADDR,(char *)&allowReuse,
sizeof(allowReuse))<0)
{
close(sock);
ERROR0("problems setsockopt'ing\n");
return -1;
}
if(bind(sock,addrp,addrlen)<0) {
ERROR1("unable to bind port %i, maybe MPD is still running?\n",
port);
close(sock);
return -1;
}
if(listen(sock,5)<0) {
close(sock);
ERROR0("problems listen'ing\n");
return -1;
}
return sock;
}
void getConnections(int sock) {
fd_set fdsr;
int fd = 0;
struct timeval tv;
tv.tv_sec = tv.tv_usec = 0;
struct sockaddr sockAddr;
socklen_t socklen = sizeof(sockAddr);
fflush(NULL);
FD_ZERO(&fdsr);
FD_SET(sock,&fdsr);
if(select(sock+1,&fdsr,NULL,NULL,&tv)==1 &&
((fd = accept(sock,&sockAddr,&socklen)) >= 0)) {
openAInterface(fd,&sockAddr);
}
else if(fd<0) ERROR0("Problems accept()'ing\n");
}
/* the Music Player Daemon (MPD)
* (c)2003 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 "log.h"
#include "conf.h"
#include "myfprintf.h"
#include <string.h>
int logLevel = LOG_LEVEL_LOW;
void initLog() {
if(strcmp(getConf()[CONF_LOG_LEVEL],"default")==0) {
if(logLevel<LOG_LEVEL_LOW) logLevel = LOG_LEVEL_LOW;
}
else if(strcmp(getConf()[CONF_LOG_LEVEL],"secure")==0) {
if(logLevel<LOG_LEVEL_SECURE) logLevel = LOG_LEVEL_SECURE;
}
else if(strcmp(getConf()[CONF_LOG_LEVEL],"verbose")==0) {
if(logLevel<LOG_LEVEL_DEBUG) logLevel = LOG_LEVEL_DEBUG;
}
else ERROR1("unknown log level \"%s\"\n",getConf()[CONF_LOG_LEVEL]);
}
/* the Music Player Daemon (MPD)
* (c)2003 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 LOG_H
#define LOG_H
#include "myfprintf.h"
#define LOG_LEVEL_LOW 0
#define LOG_LEVEL_SECURE 1
#define LOG_LEVEL_DEBUG 2
extern int logLevel;
#define ERROR0(x) myfprintf(stderr,x);
#define ERROR1(x,a) myfprintf(stderr,x,a);
#define ERROR2(x,a,b) myfprintf(stderr,x,a,b);
#define ERROR3(x,a,b,c) myfprintf(stderr,x,a,b,c);
#define LOG0(x) myfprintf(stdout,x);
#define LOG1(x,a) myfprintf(stdout,x,a);
#define SECURE0(x) if(logLevel>=LOG_LEVEL_SECURE) myfprintf(stdout,x);
#define SECURE1(x,a) if(logLevel>=LOG_LEVEL_SECURE) myfprintf(stdout,x,a);
#define SECURE2(x,a,b) if(logLevel>=LOG_LEVEL_SECURE) myfprintf(stdout,x,a,b);
#define DEBUG0(x) if(logLevel>=LOG_LEVEL_DEBUG) myfprintf(stdout,x);
#define DEBUG1(x,a) if(logLevel>=LOG_LEVEL_DEBUG) myfprintf(stdout,x,a);
#define DEBUG2(x,a,b) if(logLevel>=LOG_LEVEL_DEBUG) myfprintf(stdout,x,a,b);
void initLog();
#endif
...@@ -30,13 +30,23 @@ ...@@ -30,13 +30,23 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
char * dupAndStripPlaylistSuffix(char * file) {
int size = strlen(file)-strlen(PLAYLIST_FILE_SUFFIX)-1;
char * ret = malloc(size+1);
strncpy(ret,file,size);
ret[size] = '\0';
return ret;
}
int ls(FILE * fp, char * dirname) { int ls(FILE * fp, char * dirname) {
DIR * dir; DIR * dir;
char cwd[2]; char cwd[2];
char c; char c;
struct stat st; struct stat st;
struct dirent * ent; struct dirent * ent;
char s[MAXPATHLEN]; char s[MAXPATHLEN+1];
cwd[0] = '.'; cwd[0] = '.';
cwd[1] = '\0'; cwd[1] = '\0';
...@@ -68,31 +78,38 @@ int ls(FILE * fp, char * dirname) { ...@@ -68,31 +78,38 @@ int ls(FILE * fp, char * dirname) {
return 0; return 0;
} }
int lsPlaylists(FILE * fp) { int lsPlaylists(FILE * fp, char * path) {
DIR * dir; DIR * dir;
struct stat st; struct stat st;
struct dirent * ent; struct dirent * ent;
char * cLast; char * cLast;
char * cNext; char * cNext;
char * dup; char * dup;
char s[MAXPATHLEN]; char s[MAXPATHLEN+1];
List * list = NULL;
ListNode * node = NULL;
char * actualPath = rpp2app(path);
if((dir = opendir(playlistDir))==NULL) { if((dir = opendir(actualPath))==NULL) return 0;
myfprintf(fp,"%s problems opening playlist directory\n",COMMAND_RESPOND_ERROR);
return -1;
}
while((ent = readdir(dir))) { while((ent = readdir(dir))) {
if(ent->d_name[0]=='.') continue; /* hide hidden stuff */ if(ent->d_name[0]=='.') continue; /* hide hidden stuff */
sprintf(s,"%s/%s",playlistDir,ent->d_name); snprintf(s,MAXPATHLEN,"%s/%s",actualPath,ent->d_name);
if(stat(s,&st)==0) { if(stat(s,&st)==0) {
if(S_ISREG(st.st_mode)) { if(S_ISREG(st.st_mode)) {
dup = strdup(ent->d_name); dup = strdup(ent->d_name);
cNext = cLast = strtok(dup,"."); cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext; while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcmp(cLast,PLAYLIST_FILE_SUFFIX)) { if(cLast && 0==strcmp(cLast,
strncpy(dup,ent->d_name,strlen(ent->d_name)-strlen(PLAYLIST_FILE_SUFFIX)-1); PLAYLIST_FILE_SUFFIX))
myfprintf(fp,"playlist: %s\n",dup); {
if(list==NULL) list = makeList(NULL);
memset(dup,0,strlen(ent->d_name));
strncpy(dup,ent->d_name,
strlen(ent->d_name)-
strlen(PLAYLIST_FILE_SUFFIX)-1);
//myfprintf(fp,"playlist: %s\n",dup);
insertInList(list,dup,NULL);
} }
free(dup); free(dup);
} }
...@@ -101,6 +118,24 @@ int lsPlaylists(FILE * fp) { ...@@ -101,6 +118,24 @@ int lsPlaylists(FILE * fp) {
closedir(dir); closedir(dir);
if(list) {
sortList(list);
dup = malloc(strlen(path)+2);
strcpy(dup,path);
while(dup[strlen(dup)-1]=='/') dup[strlen(dup)-1] = '\0';
if(strlen(dup)) strcat(dup,"/");
node = list->firstNode;
while(node!=NULL) {
myfprintf(fp,"playlist: %s%s\n",dup,node->key);
node = node->nextNode;
}
freeList(list);
free(dup);
}
return 0; return 0;
} }
...@@ -120,6 +155,35 @@ time_t isMusic(char * file) { ...@@ -120,6 +155,35 @@ time_t isMusic(char * file) {
return ret; return ret;
} }
time_t isPlaylist(char * file) {
struct stat st;
char * actualFile = file;
char * temp = NULL;
if(actualFile[0]!='/') actualFile = rpp2app(file);
if(stat(actualFile,&st)==0) {
if(S_ISREG(st.st_mode)) {
char * dup;
char * cLast;
char * cNext;
int ret = 0;
dup = strdup(file);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcmp(cLast,PLAYLIST_FILE_SUFFIX)) {
ret = st.st_mtime;
}
free(dup);
if(temp) free(temp);
return ret;
}
}
if(temp) free(temp);
return 0;
}
time_t isFlac(char * file) { time_t isFlac(char * file) {
struct stat st; struct stat st;
char * actualFile = file; char * actualFile = file;
......
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
int ls(FILE * fp, char * dir); int ls(FILE * fp, char * dir);
int lsPlaylists(FILE * fp); int lsPlaylists(FILE * fp, char * path);
time_t isMp3(char * file); time_t isMp3(char * file);
...@@ -36,4 +36,8 @@ time_t isMusic(char * file); ...@@ -36,4 +36,8 @@ time_t isMusic(char * file);
time_t isDir(char * name); time_t isDir(char * name);
time_t isPlaylist(char * file);
char * dupAndStripPlaylistSuffix(char * file);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2002 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 "interface.h"
#include "command.h"
#include "playlist.h"
#include "directory.h"
#include "tables.h"
#include "player.h"
#include "listen.h"
#include "conf.h"
#include "path.h"
#include "playerData.h"
#include "stats.h"
#include "sig_handlers.h"
#include "audio.h"
#include "volume.h"
#include "log.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <pwd.h>
#include <grp.h>
#define SYSTEM_CONFIG_FILE_LOCATION "/etc/mpd.conf"
#define USER_CONFIG_FILE_LOCATION "/.mpdconf"
typedef struct _Options {
char * portStr;
char * musicDirArg;
char * playlistDirArg;
char * logFile;
char * errorFile;
char * usr;
char * dbFile;
int daemon;
int createDB;
} Options;
void usage(char * argv[]) {
ERROR0("usage:\n");
ERROR1(" %s [options] <port> <music dir> <playlist dir> <log file> <error file>\n",argv[0]);
ERROR1(" %s [options] <conf file>\n",argv[0]);
ERROR3(" %s [options] (searches for ~%s then %s)\n",
argv[0],USER_CONFIG_FILE_LOCATION,
SYSTEM_CONFIG_FILE_LOCATION);
ERROR0("\n");
ERROR0("options:\n");
ERROR0(" --help this usage statement\n");
ERROR0(" --no-daemon don't detach from console\n");
ERROR0(" --create-db (re)create database\n");
ERROR0(" --verbose verbose logging\n");
ERROR0(" --version prints version information\n");
}
void version() {
ERROR1("mpd (MPD: Music Player Daemon) %s\n",VERSION);
ERROR0("\n");
ERROR0("Copyright (C) 2003 Warren Dukes <shank@mercury.chem.pitt.edu>\n");
ERROR0("This is free software; see the source for copying conditions. There is NO\n");
ERROR0("warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
}
void parseOptions(int argc, char ** argv, Options * options) {
int argcLeft = argc;
options->usr = NULL;
options->daemon = 1;
options->createDB = 0;
options->dbFile = NULL;
if(argc>1) {
int i = 1;
while(i<argc) {
if(strncmp(argv[i],"--",2)==0) {
if(strcmp(argv[i],"--help")==0) {
usage(argv);
exit(0);
}
else if(strcmp(argv[i],"--no-daemon")==0) {
options->daemon = 0;
argcLeft--;
}
else if(strcmp(argv[i],"--create-db")==0) {
options->createDB = 1;
argcLeft--;
}
else if(strcmp(argv[i],"--verbose")==0) {
logLevel = LOG_LEVEL_DEBUG;
argcLeft--;
}
else if(strcmp(argv[i],"--version")==0) {
version();
exit(0);
}
}
else break;
i++;
}
}
if(argcLeft==6) {
options->portStr = argv[argc-5];
options->musicDirArg = argv[argc-4];
options->playlistDirArg = argv[argc-3];
options->logFile = argv[argc-2];
options->errorFile = argv[argc-1];
return;
}
else if(argcLeft<=2) {
char ** conf = NULL;
if(argcLeft==2) conf = readConf(argv[argc-1]);
if(argcLeft==1) {
FILE * fp;
char * homedir = getenv("HOME");
char userfile[MAXPATHLEN+1] = "";
if(homedir && (strlen(homedir)+
strlen(USER_CONFIG_FILE_LOCATION)) <
MAXPATHLEN) {
strcpy(userfile,homedir);
strcat(userfile,USER_CONFIG_FILE_LOCATION);
}
if(strlen(userfile) && (fp=fopen(userfile,"r"))) {
fclose(fp);
conf = readConf(userfile);
}
else if((fp=fopen(SYSTEM_CONFIG_FILE_LOCATION,"r"))) {
fclose(fp);
conf = readConf(SYSTEM_CONFIG_FILE_LOCATION);
}
}
if(conf) {
options->portStr = conf[CONF_PORT];
options->musicDirArg = conf[CONF_MUSIC_DIRECTORY];
options->playlistDirArg = conf[CONF_PLAYLIST_DIRECTORY];
options->logFile = conf[CONF_LOG_FILE];
options->errorFile = conf[CONF_ERROR_FILE];
options->usr = conf[CONF_USER];
if(conf[CONF_DB_FILE]) {
options->dbFile = conf[CONF_DB_FILE];
}
return;
}
}
usage(argv);
exit(-1);
}
int main(int argc, char * argv[]) {
int port, uid, gid;
struct stat st;
FILE * out;
FILE * err;
Options options;
initConf();
parseOptions(argc,argv,&options);
initLog();
if((port = atoi(options.portStr))<0) {
ERROR0("problem with port number\n");
return -1;
}
if((listenSocket = establish(port))<0) {
ERROR0("error binding port\n");
return -1;
}
/*
* lose privileges as early as possible
*/
/* change uid */
if (options.usr && strlen(options.usr)) {
#ifdef _BSD_SOURCE
gid_t gid_list[NGROUPS_MAX];
#endif
/* get uid */
struct passwd * userpwd;
if ((userpwd = getpwnam(options.usr)) == NULL) {
ERROR1("no such user: %s\n", options.usr);
return -1;
}
uid = userpwd->pw_uid;
gid = userpwd->pw_gid;
if(setgid(gid) == -1) {
ERROR2("cannot setgid of user %s: %s\n", options.usr,
strerror(errno));
return -1;
}
#ifdef _BSD_SOURCE
/* init suplementary groups
* (must be done before we change our uid)
*/
if (initgroups(options.usr, gid) == -1) {
ERROR2("cannot init suplementary groups "
"of user %s: %s\n", options.usr,
strerror(errno));
}
else if(getgroups(NGROUPS_MAX, gid_list) == -1) {
ERROR2("cannot get groups "
"of user %s: %s\n", options.usr,
strerror(errno));
return -1;
}
else if(setgroups(NGROUPS_MAX, gid_list) == -1) {
ERROR2("cannot set groups "
"of user %s: %s\n", options.usr,
strerror(errno));
return -1;
}
#endif
/* set uid */
if (setuid(uid) == -1) {
ERROR2("cannot change to uid of user "
"%s: %s\n", options.usr,
strerror(errno));
return -1;
}
}
if(NULL==(out=fopen(options.logFile,"a"))) {
ERROR1("problem opening file \"%s\" for writing\n",
options.logFile);
return -1;
}
if(NULL==(err=fopen(options.errorFile,"a"))) {
ERROR1("problem opening file \"%s\" for writing\n",
options.errorFile);
return -1;
}
if(options.playlistDirArg[0]=='/') {
strcpy(playlistDir,options.playlistDirArg);
}
else {
getcwd(playlistDir,MAXPATHLEN-strlen(options.playlistDirArg)-1);
if(playlistDir[strlen(playlistDir)-1]!='/') {
strcat(playlistDir,"/");
}
strcat(playlistDir,options.playlistDirArg);
}
if(playlistDir[strlen(playlistDir)-1]!='/') {
strcat(playlistDir,"/");
}
if((stat(playlistDir,&st))<0) {
ERROR1("problem stat'ing \"%s\"\n",options.playlistDirArg);
return -1;
}
if(!S_ISDIR(st.st_mode)) {
ERROR1("\"%s\" is not a directory\n",options.playlistDirArg);
return -1;
}
if(options.musicDirArg[0]=='/') {
strcpy(musicDir,options.musicDirArg);
}
else {
getcwd(musicDir,MAXPATHLEN-strlen(options.musicDirArg)-1);
if(musicDir[strlen(musicDir)-1]!='/') strcat(musicDir,"/");
strcat(musicDir,options.musicDirArg);
}
if(musicDir[strlen(musicDir)-1]!='/') strcat(musicDir,"/");
if((stat(musicDir,&st))<0) {
ERROR1("problem stat'ing \"%s\"\n",options.musicDirArg);
return -1;
}
if(!S_ISDIR(st.st_mode)) {
ERROR1("\"%s\" is not a directory\n",options.musicDirArg);
return -1;
}
initTables();
if(!options.dbFile) {
strncpy(directorydb,playlistDir,MAXPATHLEN);
strncat(directorydb,"/.mpddb",MAXPATHLEN-strlen(playlistDir));
}
else strncpy(directorydb,options.dbFile,MAXPATHLEN);
if(options.createDB || readDirectoryDB()<0) {
initMp3Directory();
if(writeDirectoryDB()<0) {
ERROR0("problem opening db for reading or writing\n");
exit(-1);
}
}
initAudioDriver();
initVolume();
initPlayerData();
initInterfaces();
initStats();
initPlaylist();
if(options.daemon) {
int pid = fork();
if(pid>0) _exit(0);
else if(pid<0) {
ERROR0("problems fork'ing for daemon!\n");
exit(-1);
}
if(chdir("/")<0) {
ERROR0("problems changing to root directory\n");
exit(-1);
}
if(close(STDOUT_FILENO)) {
fprintf(err,"problems closing stdout : %s\n",
strerror(errno));
exit(-1);
}
if(close(STDERR_FILENO)) {
fprintf(err,"problems closing stderr : %s\n",
strerror(errno));
exit(-1);
}
if(dup2(fileno(out),STDOUT_FILENO)<0) {
fprintf(err,"problems dup2 stdout : %s\n",
strerror(errno));
exit(-1);
}
if(dup2(fileno(err),STDERR_FILENO)<0) {
fprintf(err,"problems dup2 stderr : %s\n",
strerror(errno));
exit(-1);
}
myfprintfStdLogMode(out,err);
}
else {
fclose(out);
fclose(err);
}
fclose(stdin);
/* lets redirect stdin to dev null as a work around for libao bug */
{
int fd = open("/dev/null",O_RDONLY);
if(fd<0) {
ERROR1("not able to open /dev/null to redirect stdin: "
"%s\n",strerror(errno));
exit(-1);
}
if(dup2(fd,STDIN_FILENO)<0) {
ERROR1("problems dup2's stdin for redirection: "
"%s\n",strerror(errno));
exit(-1);
}
}
openVolumeDevice();
initSigHandlers();
readPlaylistState();
while(COMMAND_RETURN_KILL!=doIOForInterfaces()) {
syncPlayerAndPlaylist();
closeOldInterfaces();
}
finishSigHandlers();
savePlaylistState();
playerKill();
freeAllInterfaces();
close(listenSocket);
closeMp3Directory();
closeTables();
finishPlaylist();
freePlayerData();
finishAudioDriver();
finishVolume();
return 0;
}
...@@ -19,34 +19,21 @@ ...@@ -19,34 +19,21 @@
#ifdef HAVE_MAD #ifdef HAVE_MAD
#include "mp3_decode.h" #include "mp3_decode.h"
#include "player.h"
#include "command.h"
#include "utils.h"
#include "audio.h"
#ifdef USE_MPD_MAD #ifdef USE_MPD_MAD
#include "libmad/mad.h" #include "libmad/mad.h"
#else #else
#include <mad.h> #include <mad.h>
#endif #endif
#include "buffer.h" #include "playerData.h"
#include "log.h"
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h> #include <sys/stat.h>
#include <sys/wait.h> #include <unistd.h>
#include <signal.h>
#include <ao/ao.h>
#define INPUT_BUFFER_SIZE 80
#define TIME_TELL_INTERVAL 0.2
#define CHECK_INPUT_FREQ 300 /* about once very 0.1 seconds */ #define FRAMES_CUSHION 2000
#define READ_BUFFER_SIZE 40960 #define READ_BUFFER_SIZE 40960
...@@ -54,10 +41,6 @@ ...@@ -54,10 +41,6 @@
#define DECODE_CONT -1 #define DECODE_CONT -1
#define DECODE_OK 0 #define DECODE_OK 0
int mp3_decode_pid = 0;
int mp3_decode_done = 0;
ao_device * mp3_device = 0;
/* this is stolen from mpg321! */ /* this is stolen from mpg321! */
struct audio_dither { struct audio_dither {
mad_fixed_t error[3]; mad_fixed_t error[3];
...@@ -125,31 +108,47 @@ typedef struct _mp3DecodeData { ...@@ -125,31 +108,47 @@ typedef struct _mp3DecodeData {
char outputBuffer[CHUNK_SIZE]; char outputBuffer[CHUNK_SIZE];
char * outputPtr; char * outputPtr;
char * outputBufferEnd; char * outputBufferEnd;
unsigned long frameCount;
int status;
float totalTime; float totalTime;
float elapsedTime; float elapsedTime;
int start; int muteFrame;
long * frameOffset;
mad_timer_t * times;
long highestFrame;
long currentOffset;
long maxFrames;
long currentFrame;
int flush;
} mp3DecodeData; } mp3DecodeData;
void initMp3DecodeData(mp3DecodeData * data) { void initMp3DecodeData(mp3DecodeData * data) {
data->outputPtr = data->outputBuffer; data->outputPtr = data->outputBuffer;
data->outputBufferEnd = data->outputBuffer+CHUNK_SIZE; data->outputBufferEnd = data->outputBuffer+CHUNK_SIZE;
data->frameCount = 0; data->muteFrame = 0;
data->status = 0; data->currentOffset = 0;
data->start = 0; data->highestFrame = 0;
data->maxFrames = 0;
data->frameOffset = NULL;
data->times = NULL;
data->currentFrame = 0;
data->flush = 1;
mad_stream_init(&data->stream); mad_stream_init(&data->stream);
mad_frame_init(&data->frame); mad_frame_init(&data->frame);
mad_synth_init(&data->synth); mad_synth_init(&data->synth);
mad_timer_reset(&data->timer); mad_timer_reset(&data->timer);
} }
int fillMp3InputBuffer(mp3DecodeData * data) { int fillMp3InputBuffer(mp3DecodeData * data, long offset) {
size_t readSize; size_t readSize;
size_t remaining; size_t remaining;
unsigned char * readStart; unsigned char * readStart;
if((data->stream).next_frame!=NULL) { if(offset>=0) {
if(fseek(data->fp,offset,SEEK_SET)==0) {
data->currentOffset = offset;
}
}
if(offset==-1 && (data->stream).next_frame!=NULL) {
remaining = (data->stream).bufend-(data->stream).next_frame; remaining = (data->stream).bufend-(data->stream).next_frame;
memmove(data->readBuffer,(data->stream).next_frame,remaining); memmove(data->readBuffer,(data->stream).next_frame,remaining);
readStart = (data->readBuffer)+remaining; readStart = (data->readBuffer)+remaining;
...@@ -164,53 +163,192 @@ int fillMp3InputBuffer(mp3DecodeData * data) { ...@@ -164,53 +163,192 @@ int fillMp3InputBuffer(mp3DecodeData * data) {
readSize = fread(readStart,1,readSize,data->fp); readSize = fread(readStart,1,readSize,data->fp);
if(readSize<=0) return -1; if(readSize<=0) return -1;
data->currentOffset+=readSize;
mad_stream_buffer(&data->stream,data->readBuffer,readSize+remaining); mad_stream_buffer(&data->stream,data->readBuffer,readSize+remaining);
(data->stream).error = 0; (data->stream).error = 0;
return 0; return 0;
} }
int decodeNextFrame(mp3DecodeData * data) { int decodeNextFrameHeader(mp3DecodeData * data) {
if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
if(fillMp3InputBuffer(data) < 0) return DECODE_BREAK; if(fillMp3InputBuffer(data,/*data->currentOffset*/-1) < 0) {
return DECODE_BREAK;
}
}
if(mad_header_decode(&data->frame.header,&data->stream)) {
if(MAD_RECOVERABLE((data->stream).error)) return DECODE_CONT;
else {
if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT;
else
{
ERROR1("unrecoverable frame level error "
"(%s).\n",
mad_stream_errorstr(&data->stream));
data->flush = 0;
return DECODE_BREAK;
}
}
}
return DECODE_OK;
}
int decodeNextFrame(mp3DecodeData * data) {
if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN) {
if(fillMp3InputBuffer(data,/*data->currentOffset*/-1) < 0) {
return DECODE_BREAK;
}
}
if(mad_frame_decode(&data->frame,&data->stream)) { if(mad_frame_decode(&data->frame,&data->stream)) {
if(MAD_RECOVERABLE((data->stream).error)) return DECODE_CONT; if(MAD_RECOVERABLE((data->stream).error)) return DECODE_CONT;
else { else {
if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT; if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT;
else else
{ {
fprintf(stderr,"unrecoverable frame level error (%s).\n",mad_stream_errorstr(&data->stream)); ERROR1("unrecoverable frame level error "
data->status = 1; "(%s).\n",
mad_stream_errorstr(&data->stream));
data->flush = 0;
return DECODE_BREAK; return DECODE_BREAK;
} }
} }
} }
data->frameCount++;
return DECODE_OK; return DECODE_OK;
} }
int openMp3(char * file, mp3DecodeData * data) { /* xing stuff stolen from alsaplayer */
int ret; # define XING_MAGIC (('X' << 24) | ('i' << 16) | ('n' << 8) | 'g')
struct xing {
long flags; /* valid fields (see below) */
unsigned long frames; /* total number of frames */
unsigned long bytes; /* total number of bytes */
unsigned char toc[100]; /* 100-point seek table */
long scale; /* ?? */
};
enum {
XING_FRAMES = 0x00000001L,
XING_BYTES = 0x00000002L,
XING_TOC = 0x00000004L,
XING_SCALE = 0x00000008L
};
int parse_xing(struct xing *xing, struct mad_bitptr ptr, unsigned int bitlen)
{
if (bitlen < 64 || mad_bit_read(&ptr, 32) != XING_MAGIC) goto fail;
xing->flags = mad_bit_read(&ptr, 32);
bitlen -= 64;
if (xing->flags & XING_FRAMES) {
if (bitlen < 32) goto fail;
xing->frames = mad_bit_read(&ptr, 32);
bitlen -= 32;
}
if (xing->flags & XING_BYTES) {
if (bitlen < 32) goto fail;
xing->bytes = mad_bit_read(&ptr, 32);
bitlen -= 32;
}
if (xing->flags & XING_TOC) {
int i;
if (bitlen < 800) goto fail;
for (i = 0; i < 100; ++i) xing->toc[i] = mad_bit_read(&ptr, 8);
bitlen -= 800;
}
if (xing->flags & XING_SCALE) {
if (bitlen < 32) goto fail;
xing->scale = mad_bit_read(&ptr, 32);
bitlen -= 32;
}
return 1;
fail:
xing->flags = 0;
return 0;
}
int decodeFirstFrame(mp3DecodeData * data) {
struct stat filestat; struct stat filestat;
struct xing xing;
int ret;
initMp3DecodeData(data); memset(&xing,0,sizeof(struct xing));
xing.flags = 0;
while((ret = decodeNextFrameHeader(data))==DECODE_CONT);
if(ret!=DECODE_OK) return -1;
while((ret = decodeNextFrame(data))==DECODE_CONT);
if(ret!=DECODE_OK) return -1;
if(parse_xing(&xing,data->stream.anc_ptr,data->stream.anc_bitlen)) {
if(xing.flags & XING_FRAMES) {
mad_timer_t duration = data->frame.header.duration;
mad_timer_multiply(&duration,xing.frames);
data->muteFrame = 1;
data->totalTime = ((float)mad_timer_count(duration,
MAD_UNITS_MILLISECONDS))/1000;
data->maxFrames = xing.frames;
}
}
else {
mad_timer_t duration = data->frame.header.duration;
float frameTime = ((float)mad_timer_count(duration,
MAD_UNITS_MILLISECONDS))/1000;
fstat(fileno(data->fp),&filestat);
data->totalTime = (filestat.st_size*8.0)/
(data->frame).header.bitrate;
data->maxFrames = data->totalTime/frameTime+FRAMES_CUSHION;
}
data->frameOffset = malloc(sizeof(long)*data->maxFrames);
data->times = malloc(sizeof(mad_timer_t)*data->maxFrames);
return 0;
}
void mp3DecodeDataFinalize(mp3DecodeData * data) {
mad_synth_finish(&data->synth);
mad_frame_finish(&data->frame);
mad_stream_finish(&data->stream);
if(data->fp) fclose(data->fp);
if(data->frameOffset) free(data->frameOffset);
if(data->times) free(data->times);
}
int openMp3(char * file, mp3DecodeData * data) {
if((data->fp = fopen(file,"r"))<=0) { if((data->fp = fopen(file,"r"))<=0) {
fprintf(stderr,"problems opening \"%s\"\n",file); ERROR1("problems opening \"%s\"\n",file);
return -1;
}
initMp3DecodeData(data);
if(decodeFirstFrame(data)<0) {
mp3DecodeDataFinalize(data);
return -1; return -1;
} }
fstat(fileno(data->fp),&filestat);
while((ret=decodeNextFrame(data))==DECODE_CONT);
data->totalTime = (filestat.st_size*8.0)/(data->frame).header.bitrate;
return ret; return 0;
} }
void mp3ChildSendData(mp3DecodeData * data, Buffer * cb) { int mp3ChildSendData(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
while(cb->begin==cb->end && cb->wrap) usleep(100); while(cb->begin==cb->end && cb->wrap && !dc->stop && !dc->seek)
usleep(10);
if(dc->stop) return -1;
/* just for now, so it doesn't hang */
if(dc->seek) return 0;
/* be sure to remove this! */
memcpy(cb->chunks[cb->end],data->outputBuffer,CHUNK_SIZE); memcpy(cb->chunks[cb->end],data->outputBuffer,CHUNK_SIZE);
cb->chunkSize[cb->end] = data->outputPtr-data->outputBuffer;
cb->times[cb->end] = data->elapsedTime; cb->times[cb->end] = data->elapsedTime;
cb->end++; cb->end++;
...@@ -218,19 +356,47 @@ void mp3ChildSendData(mp3DecodeData * data, Buffer * cb) { ...@@ -218,19 +356,47 @@ void mp3ChildSendData(mp3DecodeData * data, Buffer * cb) {
cb->end = 0; cb->end = 0;
cb->wrap = 1; cb->wrap = 1;
} }
return 0;
} }
int mp3Read(mp3DecodeData * data, Buffer * cb) { int mp3Read(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
static int i; static int i;
static int ret; static int ret;
static struct audio_dither dither; static struct audio_dither dither;
if(data->currentFrame>=data->highestFrame &&
data->highestFrame<data->maxFrames)
{
mad_timer_add(&data->timer,(data->frame).header.duration); mad_timer_add(&data->timer,(data->frame).header.duration);
data->frameOffset[data->currentFrame] =
data->currentOffset;
if(data->stream.this_frame!=NULL) {
data->frameOffset[data->currentFrame]+=
data->stream.this_frame-
data->stream.buffer;
}
else {
data->frameOffset[data->currentFrame]+=
data->stream.bufend-data->stream.buffer;
}
data->times[data->currentFrame] = data->timer;
data->highestFrame++;
}
else data->timer = data->times[data->currentFrame];
data->currentFrame++;
data->elapsedTime = ((float)mad_timer_count(data->timer,MAD_UNITS_MILLISECONDS))/1000;
if(data->muteFrame) {
if(!dc->seek) data->muteFrame = 0;
else if(dc->seekWhere<=data->elapsedTime) {
data->muteFrame = 0;
dc->seek = 0;
}
}
else {
mad_synth_frame(&data->synth,&data->frame); mad_synth_frame(&data->synth,&data->frame);
data->elapsedTime = ((float)mad_timer_count(data->timer,MAD_UNITS_MILLISECONDS))/1000;
for(i=0;i<(data->synth).pcm.length;i++) { for(i=0;i<(data->synth).pcm.length;i++) {
signed int sample; signed int sample;
...@@ -245,196 +411,77 @@ int mp3Read(mp3DecodeData * data, Buffer * cb) { ...@@ -245,196 +411,77 @@ int mp3Read(mp3DecodeData * data, Buffer * cb) {
} }
if(data->outputPtr==data->outputBufferEnd) { if(data->outputPtr==data->outputBufferEnd) {
mp3ChildSendData(data,cb); if(mp3ChildSendData(data,cb,dc)<0) {
data->flush = 0;
return DECODE_BREAK;
}
data->outputPtr = data->outputBuffer; data->outputPtr = data->outputBuffer;
if(dc->seek) break;
} }
} }
while((ret=decodeNextFrame(data))==DECODE_CONT); if(dc->seek) {
long i = 0;
return ret; cb->wrap = 0;
} cb->end = 0;
data->muteFrame = 1;
ao_device * initAoDeviceFromMp3DecodeData(mp3DecodeData * data) { while(i<data->highestFrame && dc->seekWhere >
ao_sample_format format; ((float)mad_timer_count(data->times[i],
ao_device * device; MAD_UNITS_MILLISECONDS))/1000)
{
format.bits = 16; i++;
format.rate = (data->frame).header.samplerate;
format.byte_format = AO_FMT_LITTLE;
format.channels = MAD_NCHANNELS(&(data->frame).header);
device = ao_open_live(audio_ao_driver_id, &format, audio_ao_options);
return device;
}
void mp3DecodeDataFinalize(mp3DecodeData * data) {
mad_synth_finish(&data->synth);
mad_frame_finish(&data->frame);
mad_stream_finish(&data->stream);
fclose(data->fp);
}
void mp3_decode_parentSigHandler(int sig) {
if(sig==SIGCHLD) {
if(mp3_decode_pid==wait3(NULL,WNOHANG,NULL)) {
mp3_decode_pid = 0;
mp3_decode_done = 1;
} }
if(i<data->highestFrame) {
data->currentFrame = i;
fillMp3InputBuffer(data,data->frameOffset[i]);
data->muteFrame = 0;
dc->seek = 0;
} }
else if(sig==SIGTERM) {
int pid = mp3_decode_pid;
if(pid>0) kill(pid,SIGTERM);
if(mp3_device) ao_close(mp3_device);
exit(0);
} }
}
/* mp3_decode w/ buffering
* this will fork another process
* child process does decoding
* parent process does buffering && playing audio
*/
int mp3_decode(char * file, FILE * in, FILE * out) {
mp3DecodeData data;
float time_total;
Buffer * cb;
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
if(openMp3(file,&data) < 0) {
fprintf(stderr,"%s Input does not appear to be a mp3 bitstream.\n",PLAYER_ERROR);
fflush(stderr);
return PLAYER_EXIT_ERROR_FILE;
} }
time_total = data.totalTime; if(data->muteFrame) {
while((ret=decodeNextFrameHeader(data))==DECODE_CONT);
cb = getBuffer(); }
cb->begin = 0; else while((ret=decodeNextFrame(data))==DECODE_CONT);
cb->end = 0;
cb->wrap = 0;
cb->finished = 0;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = mp3_decode_parentSigHandler;
sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGTERM,&sa,NULL);
fflush(NULL);
mp3_decode_pid = fork();
if(mp3_decode_pid==0) {
/* CHILD */
fclose(in);
fclose(out);
while(mp3Read(&data,cb)!=DECODE_BREAK); return ret;
}
cb->finished = 1; void initAudioFormatFromMp3DecodeData(mp3DecodeData * data, AudioFormat * af) {
af->bits = 16;
af->sampleRate = (data->frame).header.samplerate;
af->channels = MAD_NCHANNELS(&(data->frame).header);
}
mp3DecodeDataFinalize(&data); int mp3_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc) {
mp3DecodeData data;
exit(0); if(openMp3(dc->file,&data) < 0) {
/* END OF CHILD */ ERROR0("Input does not appear to be a mp3 bit stream.\n");
} return -1;
else if(mp3_decode_pid<0) {
fprintf(stderr,"%s mp3_decode Problems fork'ing\n",COMMAND_RESPOND_ERROR);
return PLAYER_EXIT_ERROR_SYSTEM;
} }
{ initAudioFormatFromMp3DecodeData(&data,af);
/* PARENT */ cb->totalTime = data.totalTime;
float elapsed = 0; dc->start = 0;
float last_tell = 0; dc->state = DECODE_STATE_DECODE;
int pause = 0;
char input[INPUT_BUFFER_SIZE+1];
int playsPerChunk = CHUNK_SIZE/PLAY_SIZE;
int currentPlayChunk = 0;
int quit = 0;
fd_set fds;
struct timeval tv;
int checkInput = 0;
int pid;
tv.tv_sec = 0;
tv.tv_usec = 0;
initAudio();
mp3_device = initAoDeviceFromMp3DecodeData(&data); while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
/* send last little bit if not dc->stop */
if(mp3_device == NULL) { if(data.outputPtr!=data.outputBuffer && data.flush) {
audioError(); mp3ChildSendData(&data,cb,dc);
pid = mp3_decode_pid;
if(pid>0) kill(pid,SIGTERM);
return PLAYER_EXIT_ERROR_AUDIO;
} }
mp3DecodeDataFinalize(&data); mp3DecodeDataFinalize(&data);
fprintf(out,"%s\n",PLAYER_START); if(dc->seek) dc->seek = 0;
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,time_total);
fflush(out);
while(mp3_decode_pid>0 && !cb->wrap && cb->end-cb->begin<buffered_before_play && !cb->finished) {
usleep(1000);
}
while(!quit) {
if(pause || checkInput%CHECK_INPUT_FREQ==0) {
FD_ZERO(&fds);
FD_SET(fileno(in),&fds);
fflush(in);
if(select(fileno(in)+1,&fds,NULL,NULL,&tv)) {
myFgets(input,INPUT_BUFFER_SIZE,in);
if(strcasecmp(PLAYER_PAUSE,input)==0) {
fprintf(out,"%s\n",PLAYER_PAUSE_GOT);
fflush(out);
pause = !pause;
}
}
checkInput = 1;
}
checkInput++;
if(pause) usleep(100);
else if(cb->begin!=cb->end || cb->wrap) {
if(currentPlayChunk==0) elapsed = cb->times[cb->begin];
ao_play(mp3_device,cb->chunks[cb->begin]+currentPlayChunk*PLAY_SIZE,PLAY_SIZE);
currentPlayChunk++;
if(currentPlayChunk>=playsPerChunk) {
currentPlayChunk=0;
cb->begin++;
if(cb->begin>=BUFFERED_CHUNKS) {
cb->begin = 0;
cb->wrap = 0;
}
}
if(elapsed-last_tell>=TIME_TELL_INTERVAL) {
last_tell = elapsed;
fprintf(out,"%s %f %f\n",PLAYER_TIME,last_tell,time_total);
fflush(out);
}
}
else if(mp3_decode_pid<=0 || cb->finished) {
quit = 1;
}
else usleep(200);
}
pid = mp3_decode_pid;
if(pid>0) kill(pid,SIGTERM);
ao_close(mp3_device); if(dc->stop) {
finishAudio(); dc->state = DECODE_STATE_STOP;
/* END OF PARENT */ dc->stop = 0;
} }
else dc->state = DECODE_STATE_STOP;
return 0; return 0;
} }
......
...@@ -19,8 +19,8 @@ ...@@ -19,8 +19,8 @@
#ifndef MP3_DECODE_H #ifndef MP3_DECODE_H
#define MP3_DECODE_H #define MP3_DECODE_H
#include <stdio.h> #include "playerData.h"
int mp3_decode(char * file, FILE * in, FILE * out); int mp3_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "myfprintf.h"
#include "interface.h"
#include <stdarg.h>
#include <sys/param.h>
#include <unistd.h>
#include <sys/select.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#define BUFFER_LENGTH MAXPATHLEN+1024
int myfprintf_stdLogMode = 0;
FILE * myfprintf_out;
FILE * myfprintf_err;
void myfprintfStdLogMode(FILE * out, FILE * err) {
myfprintf_stdLogMode = 1;
myfprintf_out = out;
myfprintf_err = err;
}
void myfprintf(FILE * fp, char * format, ... ) {
va_list arglist;
int fd = fileno(fp);
int fcntlret;
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);
}
else if(fcntl) {
char buffer[BUFFER_LENGTH+1];
vsnprintf(buffer,BUFFER_LENGTH,format,arglist);
if(interfacePrintWithFD(fd,buffer)<0) {
/* not a fd from a interface */
vfprintf(fp,format,arglist);
}
}
else vfprintf(fp,format,arglist);
fflush(fp);
va_end(arglist);
}
...@@ -16,18 +16,13 @@ ...@@ -16,18 +16,13 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "path.h" #ifndef MYFPRINTF_H
#define MYFPRINTF_H
#include <string.h> #include <stdio.h>
char musicDir[MAXPATHLEN+1]; void myfprintfStdLogMode(FILE * out, FILE * err);
char playlistDir[MAXPATHLEN+1];
char * rmp2amp(char * relativePath) { void myfprintf(FILE * fp, char * format, ... );
static char absolutePath[MAXPATHLEN+1];
strcpy(absolutePath,musicDir); #endif
strcat(absolutePath,relativePath);
return absolutePath;
}
/* the Music Player Daemon (MPD)
* (c)2003 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
*/
#ifdef HAVE_OGG
#include "ogg_decode.h"
#include "command.h"
#include "utils.h"
#include "audio.h"
#include "log.h"
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <vorbis/vorbisfile.h>
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc)
{
OggVorbis_File vf;
FILE * oggfp;
if(!(oggfp = fopen(dc->file,"r"))) {
ERROR0("failed to open ogg\n");
return -1;
}
if(ov_open(oggfp, &vf, NULL, 0) < 0) {
ERROR0("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;
struct timeval tv;
long ret;
char chunk[CHUNK_SIZE];
tv.tv_sec = 0;
tv.tv_usec = 0;
while(!eof) {
if(dc->seek) {
cb->end = 0;
cb->wrap = 0;
ov_time_seek_page(&vf,dc->seekWhere);
dc->seek = 0;
}
ret = ov_read(&vf,chunk,CHUNK_SIZE,0,2,1,
&current_section);
if(ret<=0) eof = 1;
else {
while(cb->begin==cb->end && cb->wrap &&
!dc->stop && !dc->seek)
{
usleep(10);
}
if(dc->stop) break;
else if(dc->seek) continue;
memcpy(cb->chunks[cb->end],chunk,CHUNK_SIZE);
cb->chunkSize[cb->end] = ret;
cb->times[cb->end] = ov_time_tell(&vf);
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
...@@ -19,8 +19,10 @@ ...@@ -19,8 +19,10 @@
#ifndef OGG_DECODE_H #ifndef OGG_DECODE_H
#define OGG_DECODE_H #define OGG_DECODE_H
#include "playerData.h"
#include <stdio.h> #include <stdio.h>
int ogg_decode(char * file, FILE * in, FILE * out); int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "path.h"
#include <string.h>
char musicDir[MAXPATHLEN+1];
char playlistDir[MAXPATHLEN+1];
char * rmp2amp(char * relativePath) {
static char absolutePath[MAXPATHLEN+1];
memset(absolutePath,0,MAXPATHLEN+1);
strcpy(absolutePath,musicDir);
strncat(absolutePath,relativePath,MAXPATHLEN-strlen(musicDir));
return absolutePath;
}
char * rpp2app(char * relativePath) {
static char absolutePath[MAXPATHLEN+1];
memset(absolutePath,0,MAXPATHLEN+1);
strcpy(absolutePath,playlistDir);
strncat(absolutePath,relativePath,MAXPATHLEN-strlen(musicDir));
return absolutePath;
}
char * parentPath(char * path) {
static char parentPath[MAXPATHLEN+1];
int i;
memset(parentPath,0,MAXPATHLEN+1);
strncpy(parentPath,path,MAXPATHLEN);
while(strlen(parentPath) && parentPath[strlen(parentPath)-1]=='/') {
parentPath[strlen(parentPath)-1] = '\0';
}
for(i=strlen(parentPath);i>=0;i--) {
if(parentPath[i]=='/') break;
parentPath[i] = '\0';
}
while(strlen(parentPath) && parentPath[strlen(parentPath)-1]=='/') {
parentPath[strlen(parentPath)-1] = '\0';
}
return parentPath;
}
...@@ -29,4 +29,10 @@ extern char playlistDir[MAXPATHLEN+1]; ...@@ -29,4 +29,10 @@ extern char playlistDir[MAXPATHLEN+1];
*/ */
char * rmp2amp(char * file); char * rmp2amp(char * file);
/* static char * returned */
char * rpp2app(char * file);
/* static char * returned */
char * parentPath(char * path);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "player.h"
#include "decode.h"
#include "command.h"
#include "interface.h"
#include "playlist.h"
#include "ls.h"
#include "listen.h"
#include "path.h"
#include "log.h"
#include "utils.h"
#include "tables.h"
#include "directory.h"
#include "volume.h"
#include "playerData.h"
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/wait.h>
#include <stdlib.h>
#include <signal.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#define MAX_BUFFER_LENGTH 1024
#define INPUT_BUFFER_SIZE 2*MAXPATHLEN
int player_pid = 0;
int player_termSent = 0;
void resetPlayer() {
player_pid = 0;
player_termSent = 0;
getPlayerData()->playerControl.stop = 0;
getPlayerData()->playerControl.play = 0;
getPlayerData()->playerControl.pause = 0;
getPlayerData()->playerControl.lockQueue = 0;
getPlayerData()->playerControl.unlockQueue = 0;
getPlayerData()->playerControl.state = PLAYER_STATE_STOP;
getPlayerData()->playerControl.state = PLAYER_QUEUE_UNLOCKED;
getPlayerData()->playerControl.seek = 0;
}
void player_sigHandler(int signal) {
if(signal==SIGCHLD) {
int status;
if(player_pid==wait3(&status,WNOHANG,NULL)) {
if(WIFSIGNALED(status) && WTERMSIG(status)!=SIGTERM) {
ERROR1("player process died from a "
"non-TERM signal: %i\n",
WTERMSIG(status));
}
resetPlayer();
}
}
}
int playerInit() {
player_pid = fork();
if(player_pid==0) {
PlayerControl * pc = &(getPlayerData()->playerControl);
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = decodeSigHandler;
sigaction(SIGCHLD,&sa,NULL);
sigaction(SIGTERM,&sa,NULL);
close(listenSocket);
freeAllInterfaces();
finishPlaylist();
closeMp3Directory();
closeTables();
finishVolume();
while(1) {
if(pc->play) decode();
else if(pc->stop) pc->stop = 0;
else if(pc->pause) pc->pause = 0;
else if(pc->closeAudio) {
finishAudio();
pc->closeAudio = 0;
kill(getppid(),SIGUSR1);
}
else if(pc->lockQueue) {
pc->queueLockState = PLAYER_QUEUE_LOCKED;
pc->lockQueue = 0;
}
else if(pc->unlockQueue) {
pc->queueLockState = PLAYER_QUEUE_UNLOCKED;
pc->unlockQueue = 0;
}
else usleep(10);
}
exit(0);
}
else if(player_pid<0) {
ERROR0("player Problems fork()'ing\n");
player_pid = 0;
return -1;
}
return 0;
}
int playerPlay(FILE * fp, char * file) {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(fp==NULL) fp = stderr;
if(playerStop(fp)<0) return -1;
{
struct stat st;
if(stat(rmp2amp(file),&st)<0) {
strcpy(pc->erroredFile,pc->file);
pc->error = PLAYER_ERROR_FILENOTFOUND;
return 0;
}
}
if(0);
#ifdef HAVE_MAD
else if(isMp3(file)) pc->decodeType = DECODE_TYPE_MP3;
#endif
#ifdef HAVE_OGG
else if(isOgg(file)) pc->decodeType = DECODE_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
else if(isFlac(file)) pc->decodeType = DECODE_TYPE_FLAC;
#endif
else {
strcpy(pc->erroredFile,pc->file);
pc->error = PLAYER_ERROR_UNKTYPE;
return 0;
}
strcpy(pc->file,rmp2amp(file));
pc->play = 1;
if(player_pid==0 && playerInit()<0) {
pc->play = 0;
return -1;
}
while(player_pid>0 && pc->play) usleep(10);
return 0;
}
int playerStop(FILE * fp) {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
pc->stop = 1;
while(player_pid>0 && pc->stop) usleep(10);
}
pc->queueState = PLAYER_QUEUE_BLANK;
playerQueueUnlock();
return 0;
}
void playerKill() {
int pid;
PlayerControl * pc = &(getPlayerData()->playerControl);
playerStop(stderr);
playerCloseAudio(stderr);
if(player_pid>0 && pc->closeAudio) sleep(1);
pid = player_pid;
if(pid>0) kill(pid,SIGTERM);
}
int playerPause(FILE * fp) {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(player_pid>0 && pc->state!=PLAYER_STATE_STOP) {
pc->pause = 1;
while(player_pid>0 && pc->pause) usleep(10);
}
return 0;
}
int getPlayerElapsedTime() {
return (int)(getPlayerData()->playerControl.elapsedTime+0.5);
}
int getPlayerTotalTime() {
return (int)(getPlayerData()->playerControl.totalTime+0.5);
}
int getPlayerState() {
return getPlayerData()->playerControl.state;
}
void clearPlayerError() {
getPlayerData()->playerControl.error = 0;
}
int getPlayerError() {
return getPlayerData()->playerControl.error;
}
char * getPlayerErrorStr() {
static char error[2*MAXPATHLEN];
PlayerControl * pc = &(getPlayerData()->playerControl);
switch(pc->error) {
case PLAYER_ERROR_FILENOTFOUND:
sprintf(error,"file \"%s\" does not exist or is inaccesible",
pc->erroredFile);
return error;
case PLAYER_ERROR_FILE:
sprintf(error,"problems decoding \"%s\"",pc->erroredFile);
return error;
case PLAYER_ERROR_AUDIO:
sprintf(error,"problems opening audio device");
return error;
case PLAYER_ERROR_SYSTEM:
sprintf(error,"system error occured");
return error;
case PLAYER_ERROR_UNKTYPE:
sprintf(error,"file type of \"%s\" is unknown",pc->erroredFile);
return error;
default:
return NULL;
}
}
void playerCloseAudio() {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(player_pid>0) {
if(playerStop(stderr)<0) return;
pc->closeAudio = 1;
}
}
int queueSong(char * file) {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(pc->queueState==PLAYER_QUEUE_BLANK) {
strcpy(pc->file,rmp2amp(file));
if(0);
#ifdef HAVE_MAD
else if(isMp3(file)) pc->decodeType = DECODE_TYPE_MP3;
#endif
#ifdef HAVE_OGG
else if(isOgg(file)) pc->decodeType = DECODE_TYPE_OGG;
#endif
#ifdef HAVE_FLAC
else if(isFlac(file)) pc->decodeType = DECODE_TYPE_FLAC;
#endif
else return -1;
pc->queueState = PLAYER_QUEUE_FULL;
return 0;
}
return -1;
}
int getPlayerQueueState() {
PlayerControl * pc = &(getPlayerData()->playerControl);
return pc->queueState;
}
void setQueueState(int queueState) {
PlayerControl * pc = &(getPlayerData()->playerControl);
pc->queueState = queueState;
}
void playerQueueLock() {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_UNLOCKED)
{
pc->lockQueue = 1;
while(player_pid>0 && pc->lockQueue) usleep(10);
}
}
void playerQueueUnlock() {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(player_pid>0 && pc->queueLockState==PLAYER_QUEUE_LOCKED)
{
pc->unlockQueue = 1;
while(player_pid>0 && pc->unlockQueue) usleep(10);
}
}
int playerSeek(FILE * fp, char * file, float time) {
PlayerControl * pc = &(getPlayerData()->playerControl);
if(pc->state==PLAYER_STATE_STOP) {
myfprintf(fp,"%s player not currently playing\n",
COMMAND_RESPOND_ERROR);
return -1;
}
if(strcmp(pc->file,rmp2amp(file))!=0) strcpy(pc->file,rmp2amp(file));
/*if(playerStop(fp)<0) return -1;
if(playerPlay(stderr,file)<0) return -1;*/
/*}*/
if(pc->error==PLAYER_ERROR_NOERROR) {
pc->seekWhere = time;
pc->seek = 1;
while(player_pid>0 && pc->seek) usleep(10);
}
return 0;
}
...@@ -20,21 +20,51 @@ ...@@ -20,21 +20,51 @@
#define PLAYER_H #define PLAYER_H
#include <stdio.h> #include <stdio.h>
#include <sys/param.h>
#define PLAYER_STATE_STOP 0 #define PLAYER_STATE_STOP 0
#define PLAYER_STATE_PAUSE 1 #define PLAYER_STATE_PAUSE 1
#define PLAYER_STATE_PLAY 2 #define PLAYER_STATE_PLAY 2
#define PLAYER_ERROR "@ERROR" #define PLAYER_ERROR_NOERROR 0
#define PLAYER_START "@START" #define PLAYER_ERROR_FILE 1
#define PLAYER_TIME "@TIME" #define PLAYER_ERROR_AUDIO 2
#define PLAYER_PAUSE_GOT "@PAUSE_GOT" #define PLAYER_ERROR_SYSTEM 3
#define PLAYER_ERROR_UNKTYPE 4
#define PLAYER_ERROR_FILENOTFOUND 5
#define PLAYER_PAUSE "pause" /* 0->1->2->3->5 regular playback
* ->4->0 don't play queued song
#define PLAYER_EXIT_ERROR_FILE 1 */
#define PLAYER_EXIT_ERROR_AUDIO 2 #define PLAYER_QUEUE_BLANK 0
#define PLAYER_EXIT_ERROR_SYSTEM 3 #define PLAYER_QUEUE_FULL 1
#define PLAYER_QUEUE_DECODE 2
#define PLAYER_QUEUE_PLAY 3
#define PLAYER_QUEUE_STOP 4
#define PLAYER_QUEUE_EMPTY 5
#define PLAYER_QUEUE_UNLOCKED 0
#define PLAYER_QUEUE_LOCKED 1
typedef struct _PlayerControl {
int decodeType;
int stop;
int play;
int pause;
int state;
int closeAudio;
int error;
float totalTime;
float elapsedTime;
char file[MAXPATHLEN+1];
char erroredFile[MAXPATHLEN+1];
int queueState;
int queueLockState;
int lockQueue;
int unlockQueue;
int seek;
double seekWhere;
} PlayerControl;
void player_sigHandler(int signal); void player_sigHandler(int signal);
...@@ -44,6 +74,10 @@ int playerPause(FILE * fp); ...@@ -44,6 +74,10 @@ int playerPause(FILE * fp);
int playerStop(FILE * fp); int playerStop(FILE * fp);
void playerCloseAudio();
void playerKill();
void playerProcessMessages(); void playerProcessMessages();
int getPlayerTotalTime(); int getPlayerTotalTime();
...@@ -54,6 +88,22 @@ int getPlayerState(); ...@@ -54,6 +88,22 @@ int getPlayerState();
void clearPlayerError(); void clearPlayerError();
char * getPlayerError(); char * getPlayerErrorStr();
int getPlayerError();
int playerInit();
int queueSong(char * file);
int getPlayerQueueState();
void setQueueState(int queueState);
void playerQueueLock();
void playerQueueUnlock();
int playerSeek(FILE * fp, char * file, float time);
#endif #endif
...@@ -16,9 +16,9 @@ ...@@ -16,9 +16,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "buffer.h" #include "playerData.h"
#include "command.h"
#include "conf.h" #include "conf.h"
#include "log.h"
#include <sys/types.h> #include <sys/types.h>
#include <sys/ipc.h> #include <sys/ipc.h>
...@@ -28,16 +28,18 @@ ...@@ -28,16 +28,18 @@
int buffered_before_play; int buffered_before_play;
int buffer_shmid; PlayerData * playerData_pd;
Buffer * buffer_b;
void initBuffer() { void initPlayerData() {
float perc; float perc;
char * test; char * test;
int shmid;
perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test); perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test);
if(*test!='%' || perc<0 || perc>100) { if(*test!='%' || perc<0 || perc>100) {
fprintf(stderr,"buffered before play \"%s\" is not a positive percentage and less than 100 percent\n",(getConf())[CONF_BUFFER_BEFORE_PLAY]); ERROR1("buffered before play \"%s\" is not a positive "
"percentage and less than 100 percent\n",
(getConf())[CONF_BUFFER_BEFORE_PLAY]);
exit(-1); exit(-1);
} }
buffered_before_play = (perc/100)*BUFFERED_CHUNKS; buffered_before_play = (perc/100)*BUFFERED_CHUNKS;
...@@ -46,24 +48,42 @@ void initBuffer() { ...@@ -46,24 +48,42 @@ void initBuffer() {
} }
else if(buffered_before_play<0) buffered_before_play = 0; else if(buffered_before_play<0) buffered_before_play = 0;
if((buffer_shmid = shmget(IPC_PRIVATE,sizeof(Buffer),IPC_CREAT|0666))<0) { if((shmid = shmget(IPC_PRIVATE,sizeof(PlayerData),IPC_CREAT|0600))<0) {
fprintf(stderr,"%s shmget'ing\n",COMMAND_RESPOND_ERROR); ERROR0("problems shmget'ing\n");
exit(-1); exit(-1);
} }
if((buffer_b = shmat(buffer_shmid,NULL,0))<0) { if((playerData_pd = shmat(shmid,NULL,0))<0) {
fprintf(stderr,"%s shmat'ing\n",COMMAND_RESPOND_ERROR); ERROR0("problems shmat'ing\n");
exit(-1); exit(-1);
} }
if (shmctl(buffer_shmid, IPC_RMID, 0)<0) { if (shmctl(shmid, IPC_RMID, 0)<0) {
fprintf(stderr,"%s shmctl'ing\n",COMMAND_RESPOND_ERROR); ERROR0("problems shmctl'ing\n");
exit(-1); exit(-1);
} }
playerData_pd->playerControl.stop = 0;
playerData_pd->playerControl.pause = 0;
playerData_pd->playerControl.play = 0;
playerData_pd->playerControl.error = 0;
playerData_pd->playerControl.lockQueue = 0;
playerData_pd->playerControl.unlockQueue = 0;
playerData_pd->playerControl.state = PLAYER_STATE_STOP;
playerData_pd->playerControl.queueState = PLAYER_QUEUE_BLANK;
playerData_pd->playerControl.queueLockState = PLAYER_QUEUE_UNLOCKED;
playerData_pd->playerControl.seek = 0;
playerData_pd->playerControl.file[0] = '\0';
playerData_pd->decoderControl.stop = 0;
playerData_pd->decoderControl.start = 0;
playerData_pd->decoderControl.state = DECODE_STATE_STOP;
playerData_pd->decoderControl.seek = 0;
playerData_pd->decoderControl.file[0] = '\0';
} }
Buffer * getBuffer() { PlayerData * getPlayerData() {
return buffer_b; return playerData_pd;
} }
void freeBuffer() { void freePlayerData() {
shmdt(buffer_b); shmdt(playerData_pd);
} }
...@@ -16,28 +16,45 @@ ...@@ -16,28 +16,45 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#ifndef BUFFER_H #ifndef PLAYER_DATA_H
#define BUFFER_H #define PLAYER_DATA_H
#include "audio.h"
#include "player.h"
#include "decode.h"
/*
#define CHUNK_SIZE 256 #define CHUNK_SIZE 256
#define BUFFERED_CHUNKS 8192 /* 2 MB of buffer */ #define BUFFERED_CHUNKS 8192
#define PLAY_SIZE 64 #define PLAY_SIZE 64
*/
#define CHUNK_SIZE 64
#define BUFFERED_CHUNKS 32768 /* 2 MB of buffer */
extern int buffered_before_play; extern int buffered_before_play;
typedef struct _Buffer { typedef struct _Buffer {
char chunks[BUFFERED_CHUNKS][CHUNK_SIZE]; char chunks[BUFFERED_CHUNKS][CHUNK_SIZE];
unsigned char chunkSize[BUFFERED_CHUNKS];
float times[BUFFERED_CHUNKS]; float times[BUFFERED_CHUNKS];
int begin; int begin;
int end; int end;
int next;
int wrap; int wrap;
int finished; float totalTime;
} Buffer; } Buffer;
void initBuffer(); typedef struct _PlayerData {
Buffer buffer;
AudioFormat audioFormat;
PlayerControl playerControl;
DecoderControl decoderControl;
} PlayerData;
void initPlayerData();
Buffer * getBuffer(); PlayerData * getPlayerData();
void freeBuffer(); void freePlayerData();
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "playlist.h"
#include "player.h"
#include "command.h"
#include "ls.h"
#include "tag.h"
#include "conf.h"
#include "directory.h"
#include "stats.h"
#include "log.h"
#include "path.h"
#include "utils.h"
#include "sig_handlers.h"
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <sys/param.h>
#include <errno.h>
#include <unistd.h>
#include <time.h>
#define BITS_FOR_VERSION 31
#define PLAYLIST_COMMENT '#'
#define PLAYLIST_STATE_STOP 0
#define PLAYLIST_STATE_PLAY 1
#define PLAYLIST_PREV_UNLESS_ELAPSED 10
#define PLAYLIST_STATE_FILE_STATE "state: "
#define PLAYLIST_STATE_FILE_RANDOM "random: "
#define PLAYLIST_STATE_FILE_REPEAT "repeat: "
#define PLAYLIST_STATE_FILE_CURRENT "current: "
#define PLAYLIST_STATE_FILE_TIME "time: "
#define PLAYLIST_STATE_FILE_PLAYLIST_BEGIN "playlist_begin"
#define PLAYLIST_STATE_FILE_PLAYLIST_END "playlist_end"
#define PLAYLIST_STATE_FILE_STATE_PLAY "play"
#define PLAYLIST_STATE_FILE_STATE_PAUSE "pause"
#define PLAYLIST_STATE_FILE_STATE_STOP "stop"
#define PLAYLIST_BUFFER_SIZE 2*MAXPATHLEN
typedef struct _Playlist {
Song ** songs;
int * order;
int length;
int current;
int queued;
int repeat;
int random;
unsigned long version;
} Playlist;
Playlist playlist;
int playlist_state = PLAYLIST_STATE_STOP;
int playlist_max_length;
int playlist_stopOnError;
int playlist_errorCount;
int playlist_queueError;
int playlist_saveAbsolutePaths;
char * playlist_stateFile = NULL;
void swapOrder(int a, int b);
int playPlaylistOrderNumber(FILE * fp, int orderNum);
void randomizeOrder(int start, int end);
void incrPlaylistVersion() {
static unsigned long max = ((unsigned long)1<<BITS_FOR_VERSION)-1;
playlist.version++;
if(playlist.version>=max) playlist.version = 0;
}
void initPlaylist() {
char * test;
playlist.length = 0;
playlist.repeat = 0;
playlist.version = 0;
playlist.random = 0;
playlist.queued = -1;
blockTermSignal();
playlist_max_length = strtol((getConf())[CONF_MAX_PLAYLIST_LENGTH],&test,10);
if(*test!='\0') {
ERROR1("max playlist length \"%s\" is not an integer\n",
(getConf())[CONF_MAX_PLAYLIST_LENGTH]);
exit(-1);
}
if(strcmp("yes",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
==0) {
playlist_saveAbsolutePaths = 1;
}
else if(strcmp("no",(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS])
==0) {
playlist_saveAbsolutePaths = 0;
}
else {
ERROR1("save_absolute_paths_in_playlist \"%s\" is not yes or "
"no\n",
(getConf())[CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS]);
exit(-1);
}
playlist.songs = malloc(sizeof(Song *)*playlist_max_length);
playlist.order = malloc(sizeof(Song *)*playlist_max_length);
memset(playlist.songs,(int)NULL,sizeof(char *)*playlist_max_length);
srand(time(NULL));
if(getConf()[CONF_STATE_FILE]) {
playlist_stateFile = getConf()[CONF_STATE_FILE];
}
unblockTermSignal();
}
void finishPlaylist() {
stopPlaylist(stderr);
clearPlaylist(stderr);
free(playlist.songs);
free(playlist.order);
}
int clearPlaylist(FILE * fp) {
int i;
if(stopPlaylist(fp)<0) return -1;
blockTermSignal();
for(i=0;i<playlist.length;i++) playlist.songs[i] = NULL;
playlist.length = 0;
unblockTermSignal();
incrPlaylistVersion();
return 0;
}
int showPlaylist(FILE * fp) {
int i;
for(i=0;i<playlist.length;i++) {
myfprintf(fp,"%i:%s\n",i,(playlist.songs[i])->file);
}
return 0;
}
void savePlaylistState() {
if(playlist_stateFile) {
FILE * fp;
blockTermSignal();
while(!(fp = fopen(playlist_stateFile,"w")) && errno==EINTR);
if(!fp) {
ERROR1("problems opening state file \"%s\" for "
"writing\n",playlist_stateFile);
return;
}
myfprintf(fp,"%s",PLAYLIST_STATE_FILE_STATE);
switch(playlist_state) {
case PLAYLIST_STATE_PLAY:
switch(getPlayerState()) {
case PLAYER_STATE_PAUSE:
myfprintf(fp,"%s\n",
PLAYLIST_STATE_FILE_STATE_PAUSE);
break;
default:
myfprintf(fp,"%s\n",
PLAYLIST_STATE_FILE_STATE_PLAY);
}
myfprintf(fp,"%s%i\n",PLAYLIST_STATE_FILE_CURRENT,
playlist.order[playlist.current]);
myfprintf(fp,"%s%i\n",PLAYLIST_STATE_FILE_TIME,
getPlayerElapsedTime());
break;
default:
myfprintf(fp,"%s\n",PLAYLIST_STATE_FILE_STATE_STOP);
break;
}
myfprintf(fp,"%s%i\n",PLAYLIST_STATE_FILE_RANDOM,playlist.random);
myfprintf(fp,"%s%i\n",PLAYLIST_STATE_FILE_REPEAT,playlist.repeat);
myfprintf(fp,"%s\n",PLAYLIST_STATE_FILE_PLAYLIST_BEGIN);
showPlaylist(fp);
myfprintf(fp,"%s\n",PLAYLIST_STATE_FILE_PLAYLIST_END);
while(fclose(fp) && errno==EINTR);
unblockTermSignal();
}
}
void loadPlaylistFromStateFile(FILE * fp, char * buffer, int state, int current,
int time)
{
char * temp;
int song;
if(!myFgets(buffer,PLAYLIST_BUFFER_SIZE,fp)) {
ERROR1("error parsing state file \"%s\"\n",playlist_stateFile);
exit(-1);
}
while(strcmp(buffer,PLAYLIST_STATE_FILE_PLAYLIST_END)) {
song = atoi(strtok(buffer,":"));
if(!(temp = strtok(NULL,""))) {
ERROR1("error parsing state file \"%s\"\n",
playlist_stateFile);
exit(-1);
}
if(addToPlaylist(stderr,temp)==0 && current==song) {
if(state!=PLAYER_STATE_STOP) {
playPlaylist(stderr,playlist.length-1,0);
}
if(state==PLAYER_STATE_PAUSE) {
playerPause(stderr);
seekSongInPlaylist(stderr,playlist.length-1,
time);
}
}
if(!myFgets(buffer,PLAYLIST_BUFFER_SIZE,fp)) {
ERROR1("error parsing state file \"%s\"\n",
playlist_stateFile);
exit(-1);
}
}
}
void readPlaylistState() {
if(playlist_stateFile) {
FILE * fp;
struct stat st;
int current = -1;
int time = 0;
int state = PLAYER_STATE_STOP;
char buffer[PLAYLIST_BUFFER_SIZE];
if(stat(playlist_stateFile,&st)<0) return;
if(!S_ISREG(st.st_mode)) {
ERROR1("state file \"%s\" is not a regular "
"file\n",playlist_stateFile);
exit(-1);
}
fp = fopen(playlist_stateFile,"r");
if(!fp) {
ERROR1("problems opening state file \"%s\" for "
"reading\n",playlist_stateFile);
exit(-1);
}
while(myFgets(buffer,PLAYLIST_BUFFER_SIZE,fp)) {
if(strncmp(buffer,PLAYLIST_STATE_FILE_STATE,
strlen(PLAYLIST_STATE_FILE_STATE))==0) {
if(strcmp(&(buffer
[strlen(PLAYLIST_STATE_FILE_STATE)]),
PLAYLIST_STATE_FILE_STATE_PLAY)==0) {
state = PLAYER_STATE_PLAY;
}
else if(strcmp(&(buffer
[strlen(PLAYLIST_STATE_FILE_STATE)]),
PLAYLIST_STATE_FILE_STATE_PAUSE)==0) {
state = PLAYER_STATE_PAUSE;
}
}
else if(strncmp(buffer,PLAYLIST_STATE_FILE_TIME,
strlen(PLAYLIST_STATE_FILE_TIME))==0) {
time = atoi(&(buffer
[strlen(PLAYLIST_STATE_FILE_TIME)]));
}
else if(strncmp(buffer,PLAYLIST_STATE_FILE_REPEAT,
strlen(PLAYLIST_STATE_FILE_REPEAT))==0) {
if(strcmp(&(buffer
[strlen(PLAYLIST_STATE_FILE_REPEAT)]),
"1")==0) {
setPlaylistRepeatStatus(stderr,1);
}
else setPlaylistRepeatStatus(stderr,0);
}
else if(strncmp(buffer,PLAYLIST_STATE_FILE_RANDOM,
strlen(PLAYLIST_STATE_FILE_RANDOM))==0) {
if(strcmp(&(buffer
[strlen(PLAYLIST_STATE_FILE_RANDOM)]),
"1")==0) {
setPlaylistRandomStatus(stderr,1);
}
else setPlaylistRandomStatus(stderr,0);
}
else if(strncmp(buffer,PLAYLIST_STATE_FILE_CURRENT,
strlen(PLAYLIST_STATE_FILE_CURRENT))==0) {
if(strlen(buffer)==
strlen(PLAYLIST_STATE_FILE_CURRENT)) {
ERROR1("error parsing state "
"file \"%s\"\n",
playlist_stateFile);
exit(-1);
}
current = atoi(&(buffer
[strlen(PLAYLIST_STATE_FILE_CURRENT)]));
}
else if(strncmp(buffer,
PLAYLIST_STATE_FILE_PLAYLIST_BEGIN,
strlen(PLAYLIST_STATE_FILE_PLAYLIST_BEGIN)
)==0) {
if(state==PLAYER_STATE_STOP) current = -1;
loadPlaylistFromStateFile(fp,buffer,state,
current,time);
}
}
fclose(fp);
}
}
int playlistInfo(FILE * fp,int song) {
MpdTag * tag;
int i;
int begin = 0;
int end = playlist.length;
if(song>=0) {
begin = song;
end = song+1;
}
if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
return -1;
}
for(i=begin;i<end;i++) {
myfprintf(fp,"file: %s\n",(playlist.songs[i])->file);
if((tag = (playlist.songs[i])->tag)) {
printMpdTag(fp,tag);
}
}
return 0;
}
void swapSongs(int song1, int song2) {
Song * temp;
temp = playlist.songs[song1];
playlist.songs[song1] = playlist.songs[song2];
playlist.songs[song2] = temp;
}
void queueNextSongInPlaylist() {
if(playlist.current<playlist.length-1) {
playlist.queued = playlist.current+1;
DEBUG2("playlist: queue song %i:\"%s\"\n",
playlist.queued,
playlist.songs[playlist.order[
playlist.queued]]->file);
if(queueSong(playlist.songs[playlist.order[
playlist.queued]]->file)<0) {
playlist.queued = -1;
playlist_queueError = 1;
}
}
else if(playlist.length && playlist.repeat) {
if(playlist.length>1 && playlist.random) {
randomizeOrder(0,playlist.length);
}
playlist.queued = 0;
DEBUG2("playlist: queue song %i:\"%s\"\n",
playlist.queued,
playlist.songs[playlist.order[
playlist.queued]]->file);
if(queueSong(playlist.songs[playlist.order[
playlist.queued]]->file)<0) {
playlist.queued = -1;
playlist_queueError = 1;
}
}
}
void syncPlaylistWithQueue(int queue) {
if(queue && getPlayerQueueState()==PLAYER_QUEUE_BLANK) {
queueNextSongInPlaylist();
}
else if(getPlayerQueueState()==PLAYER_QUEUE_DECODE) {
if(playlist.queued!=-1) setQueueState(PLAYER_QUEUE_PLAY);
else setQueueState(PLAYER_QUEUE_STOP);
}
else if(getPlayerQueueState()==PLAYER_QUEUE_EMPTY) {
setQueueState(PLAYER_QUEUE_BLANK);
if(playlist.queued>=0) {
DEBUG0("playlist: now playing queued song\n");
playlist.current = playlist.queued;
}
playlist.queued = -1;
if(queue) queueNextSongInPlaylist();
}
}
void lockPlaylistInteraction() {
if(getPlayerQueueState()==PLAYER_QUEUE_PLAY ||
getPlayerQueueState()==PLAYER_QUEUE_FULL) {
playerQueueLock();
syncPlaylistWithQueue(0);
}
}
void unlockPlaylistInteraction() {
playerQueueUnlock();
}
void clearPlayerQueue() {
playlist.queued = -1;
switch(getPlayerQueueState()) {
case PLAYER_QUEUE_FULL:
DEBUG0("playlist: dequeue song\n");
setQueueState(PLAYER_QUEUE_BLANK);
break;
case PLAYER_QUEUE_PLAY:
DEBUG0("playlist: stop decoding queued song\n");
setQueueState(PLAYER_QUEUE_STOP);
break;
}
}
int addToPlaylist(FILE * fp, char * file) {
Song * song;
if(!(song = getSong(file))) {
myfprintf(fp,"%s \"%s\" is not in the music db\n",COMMAND_RESPOND_ERROR,file);
return -1;
}
if(playlist.length==playlist_max_length) {
myfprintf(fp,"%s playlist is at the max size\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0 && playlist.current==playlist.length-1) {
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
playlist.songs[playlist.length] = song;
playlist.order[playlist.length] = playlist.length;
playlist.length++;
if(playlist.random) {
int swap;
int start;
if(playlist_state==PLAYLIST_STATE_STOP) start = 0;
else if(playlist.queued>0) start = playlist.queued+1;
else start = playlist.current+1;
swap = rand()%(playlist.length-start);
swap+=start;
swapOrder(playlist.length-1,swap);
}
incrPlaylistVersion();
return 0;
}
int swapSongsInPlaylist(FILE * fp, int song1, int song2) {
int queuedSong = -1;
int currentSong = -1;
if(song1<0 || song1>=playlist.length) {
fprintf(fp,"%s \"%i\" is not in the playlist\n",
COMMAND_RESPOND_ERROR,song1);
return -1;
}
if(song2<0 || song2>=playlist.length) {
fprintf(fp,"%s \"%i\" is not in the playlist\n",
COMMAND_RESPOND_ERROR,song2);
return -1;
}
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) {
queuedSong = playlist.order[playlist.queued];
}
currentSong = playlist.order[playlist.current];
if(queuedSong==song1 || queuedSong==song2 || currentSong==song1
|| currentSong==song2)
{
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
swapSongs(song1,song2);
if(playlist.random) {
int i;
int k;
int j = -1;
for(i=0;playlist.order[i]!=song1;i++) {
if(playlist.order[i]==song2) j = i;
}
k = i;
for(;j==-1;i++) if(playlist.order[i]==song2) j = i;
swapOrder(k,j);
}
else {
if(playlist.current==song1) playlist.current = song2;
else if(playlist.current==song2) playlist.current = song1;
}
unblockTermSignal();
incrPlaylistVersion();
return 0;
}
int deleteFromPlaylist(FILE * fp, int song) {
int i;
int songOrder;
if(song<0) {
myfprintf(fp,"%s need a positive integer\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
return -1;
}
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0 && (playlist.order[playlist.queued]==song
|| playlist.order[playlist.current]==song))
{
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
/* delete song from songs array */
for(i=song;i<playlist.length-1;i++) {
playlist.songs[i] = playlist.songs[i+1];
}
/* now find it in the order array */
for(i=0;i<playlist.length-1;i++) {
if(playlist.order[i]==song) break;
}
songOrder = i;
/* delete the entry from the order array */
for(;i<playlist.length-1;i++) playlist.order[i] = playlist.order[i+1];
/* readjust values in the order array */
for(i=0;i<playlist.length-1;i++) {
if(playlist.order[i]>song) playlist.order[i]--;
}
/* now take care of other misc stuff */
playlist.songs[playlist.length-1] = NULL;
playlist.length--;
unblockTermSignal();
incrPlaylistVersion();
if(playlist_state!=PLAYLIST_STATE_STOP && playlist.current==songOrder) {
/*if(playlist.current>=playlist.length) return playerStop(fp);
else return playPlaylistOrderNumber(fp,playlist.current);*/
playerStop(stderr);
}
else if(playlist_state!=PLAYLIST_STATE_STOP &&
playlist.current>songOrder) {
playlist.current--;
}
if(playlist_state!=PLAYLIST_STATE_STOP && playlist.queued>songOrder) {
playlist.queued--;
}
return 0;
}
void deleteASongFromPlaylist(Song * song) {
int i;
for(i=0;i<playlist.length;i++) {
if(song==playlist.songs[i]) {
deleteFromPlaylist(stderr,i);
}
}
}
void deleteSongsFromPlaylist(SongList * songList) {
ListNode * node = songList->firstNode;
Song * song;
while(node) {
song = (Song *)node->data;
deleteASongFromPlaylist(song);
node = node->nextNode;
}
}
int stopPlaylist(FILE * fp) {
DEBUG0("playlist: stop\n");
if(playerStop(fp)<0) return -1;
playerCloseAudio();
playlist.queued = -1;
playlist_state = PLAYLIST_STATE_STOP;
/*stats.playTime+=getPlayerElapsedTime();*/
if(playlist.random) randomizeOrder(0,playlist.length-1);
return 0;
}
int playPlaylistOrderNumber(FILE * fp, int orderNum) {
/*stats.songsPlayed++;*/
if(playerStop(fp)<0) return -1;
playlist_state = PLAYLIST_STATE_PLAY;
playlist.queued = -1;
playlist_queueError = 0;
playlist.current = orderNum;
DEBUG2("playlist: play %i:\"%s\"\n",orderNum,
(playlist.songs[playlist.order[orderNum]])->file);
if(playerPlay(fp,(playlist.songs[playlist.order[orderNum]])->file)<0) {
stopPlaylist(fp);
return -1;
}
return 0;
}
int playPlaylist(FILE * fp, int song, int stopOnError) {
int i = song;
clearPlayerError();
if(song==-1) i = 0;
else if(song<0) {
myfprintf(fp,"%s need integer >= -1\n",COMMAND_RESPOND_ERROR);
playlist_state = PLAYLIST_STATE_STOP;
return -1;
}
if(!playlist.length) {
myfprintf(fp,"%s playlist is empty\n",COMMAND_RESPOND_ERROR);
playlist_state = PLAYLIST_STATE_STOP;
return -1;
}
else if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
playlist_state = PLAYLIST_STATE_STOP;
return -1;
}
if(playlist.random) {
if(song>=0) for(i=0;song!=playlist.order[i];i++);
if(playlist_state==PLAYLIST_STATE_STOP) {
playlist.current = 0;
}
swapOrder(i,playlist.current);
i = playlist.current;
}
playlist_stopOnError = stopOnError;
playlist_errorCount = 0;
return playPlaylistOrderNumber(fp,i);
}
void playPlaylistIfPlayerStopped() {
if(getPlayerState()==PLAYER_STATE_STOP) {
int error = getPlayerError();
if(error==PLAYER_ERROR_NOERROR) playlist_errorCount = 0;
else playlist_errorCount++;
if((playlist_stopOnError && error!=PLAYER_ERROR_NOERROR) ||
error==PLAYER_ERROR_AUDIO ||
error==PLAYER_ERROR_SYSTEM ||
playlist_errorCount>=playlist.length) {
stopPlaylist(stderr);
}
else nextSongInPlaylist(stderr);
}
}
void syncPlayerAndPlaylist() {
if(playlist_state!=PLAYLIST_STATE_PLAY) return;
if(getPlayerState()==PLAYER_STATE_STOP) playPlaylistIfPlayerStopped();
else syncPlaylistWithQueue(!playlist_queueError);
}
int nextSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) return 0;
playlist_stopOnError = 0;
if(playlist.current<playlist.length-1) {
/*stats.playTime+=getPlayerElapsedTime();*/
return playPlaylistOrderNumber(fp,playlist.current+1);
}
else if(playlist.length && playlist.repeat) {
/*stats.playTime+=getPlayerElapsedTime();*/
if(playlist.random) randomizeOrder(0,playlist.length-1);
return playPlaylistOrderNumber(fp,0);
}
else return stopPlaylist(fp);;
return 0;
}
int getPlaylistRepeatStatus() {
return playlist.repeat;
}
int getPlaylistRandomStatus() {
return playlist.random;
}
int setPlaylistRepeatStatus(FILE * fp, int status) {
if(status!=0 && status!=1) {
myfprintf(fp,"%s \"%i\" is not 0 or 1\n",COMMAND_RESPOND_ERROR,status);
return -1;
}
playlist.repeat = status;
return 0;
}
int moveSongInPlaylist(FILE * fp, int from, int to) {
int i;
Song * tmpSong;
int queuedSong = -1;
int currentSong = -1;
if(from<0 || from>=playlist.length) {
fprintf(fp,"%s \"%i\" is not a song in the playlist\n",
COMMAND_RESPOND_ERROR,from);
return -1;
}
if(to<0 || to>=playlist.length) {
fprintf(fp,"%s \"%i\" is not a song in the playlist\n",
COMMAND_RESPOND_ERROR,to);
return -1;
}
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=0) {
queuedSong = playlist.order[playlist.queued];
}
currentSong = playlist.order[playlist.current];
if(queuedSong==from || queuedSong==to || currentSong==from ||
currentSong==to)
{
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
tmpSong = playlist.songs[from];
/* move songs to one less in from->to */
for(i=from;i<to;i++) playlist.songs[i] = playlist.songs[i+1];
/* move songs to one more in to->from */
for(i=from;i>to;i--) playlist.songs[i] = playlist.songs[i-1];
/* but song at _to_ */
playlist.songs[to] = tmpSong;
/* now deal with order */
if(playlist.random) {
for(i=0;i<playlist.length;i++) {
if(playlist.order[i]>from && playlist.order[i]<=to) {
playlist.order[i]--;
}
else if(playlist.order[i]<from &&
playlist.order[i]>=to) {
playlist.order[i]++;
}
else if(from==playlist.order[i]) {
playlist.order[i] = to;
}
}
}
else if(playlist.current==from) playlist.current = to;
unblockTermSignal();
incrPlaylistVersion();
return 0;
}
void orderPlaylist() {
int i;
playlist.current = playlist.order[playlist.current];
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>0) {
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
for(i=0;i<playlist.length;i++) {
playlist.order[i] = i;
}
unblockTermSignal();
}
void swapOrder(int a, int b) {
int bak = playlist.order[a];
playlist.order[a] = playlist.order[b];
playlist.order[b] = bak;
}
void randomizeOrder(int start,int end) {
int i;
int ri;
DEBUG2("playlist: randomize from %i to %i\n",start,end);
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
if(playlist.queued>=start && playlist.queued<=end) {
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
for(i=start;i<=end;i++) {
ri = rand()%(end-start+1)+start;
if(ri==playlist.current) playlist.current = i;
else if(i==playlist.current) playlist.current = ri;
swapOrder(i,ri);
}
unblockTermSignal();
}
int setPlaylistRandomStatus(FILE * fp, int status) {
int statusWas = playlist.random;
if(status!=0 && status!=1) {
myfprintf(fp,"%s \"%i\" is not 0 or 1\n",COMMAND_RESPOND_ERROR,status);
return -1;
}
playlist.random = status;
if(status!=statusWas) {
if(playlist.random) {
if(playlist_state==PLAYLIST_STATE_PLAY) {
randomizeOrder(playlist.current+1,
playlist.length-1);
}
else randomizeOrder(0,playlist.length-1);
}
else orderPlaylist();
}
return 0;
}
int previousSongInPlaylist(FILE * fp) {
if(playlist_state!=PLAYLIST_STATE_PLAY) return 0;
if (getPlayerElapsedTime()>PLAYLIST_PREV_UNLESS_ELAPSED) {
return playPlaylistOrderNumber(fp,playlist.current);
}
else {
if(playlist.current>0) {
return playPlaylistOrderNumber(fp,playlist.current-1);
}
else if(playlist.repeat) {
return playPlaylistOrderNumber(fp,playlist.length-1);
}
else {
return playPlaylistOrderNumber(fp,playlist.current);
}
}
return 0;
}
int shufflePlaylist(FILE * fp) {
int i;
int ri;
if(playlist.length>1) {
blockTermSignal();
if(playlist_state==PLAYLIST_STATE_PLAY) {
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
/* put current playing song first */
swapSongs(0,playlist.order[playlist.current]);
if(playlist.random) {
int j;
for(j=0;0!=playlist.order[j];j++);
playlist.current = j;
}
else playlist.current = 0;
i = 1;
}
else i = 0;
/* shuffle the rest of the list */
for(;i<playlist.length;i++) {
ri = rand()%(playlist.length-1)+1;
swapSongs(i,ri);
}
unblockTermSignal();
incrPlaylistVersion();
}
return 0;
}
int deletePlaylist(FILE * fp, char * file) {
struct stat st;
char * rfile = malloc(strlen(file)+strlen(".")+
strlen(PLAYLIST_FILE_SUFFIX)+1);
char * actualFile;
strcpy(rfile,file);
strcat(rfile,".");
strcat(rfile,PLAYLIST_FILE_SUFFIX);
if((actualFile = rpp2app(rfile)) && isPlaylist(actualFile)) free(rfile);
else {
free(rfile);
myfprintf(fp,"%s playlist \"%s\" not found\n",
COMMAND_RESPOND_ERROR,file);
return -1;
}
if(stat(file,&st)<0) {
myfprintf(fp,"%s problems stat'ing\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(!S_ISREG(st.st_mode)) {
myfprintf(fp,"%s not a file\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(unlink(file)<0) {
myfprintf(fp,"%s problems deleting file\n",COMMAND_RESPOND_ERROR);
return -1;
}
return 0;
}
int savePlaylist(FILE * fp, char * file) {
FILE * fileP;
int i;
struct stat st;
char * rfile;
char * actualFile;
if(strstr(file,"/")) {
myfprintf(fp,"%s cannot save \"%s\", saving playlists to "
"subdirectories is not supported\n",
COMMAND_RESPOND_ERROR,file);
return -1;
}
rfile = malloc(strlen(file)+strlen(".")+
strlen(PLAYLIST_FILE_SUFFIX)+1);
strcpy(rfile,file);
strcat(rfile,".");
strcat(rfile,PLAYLIST_FILE_SUFFIX);
actualFile = rpp2app(rfile);
free(rfile);
if(0==stat(actualFile,&st)) {
myfprintf(fp,"%s A file or directory already exists with the name \"%s\"\n",COMMAND_RESPOND_ERROR,file);
return -1;
}
while(!(fileP = fopen(actualFile,"w")) && errno==EINTR);
if(fileP==NULL) {
myfprintf(fp,"%s Problems opening file\n",COMMAND_RESPOND_ERROR);
return -1;
}
for(i=0;i<playlist.length;i++) {
if(playlist_saveAbsolutePaths) {
myfprintf(fileP,"%s%s\n",musicDir,
(playlist.songs[i])->file);
}
else myfprintf(fileP,"%s\n",(playlist.songs[i])->file);
}
while(fclose(fileP) && errno==EINTR);
return 0;
}
int loadPlaylist(FILE * fp, char * file) {
FILE * fileP;
char s[MAXPATHLEN+1];
int slength = 0;
char * rfile = malloc(strlen(file)+strlen(".")+
strlen(PLAYLIST_FILE_SUFFIX)+1);
char * actualFile;
char * parent = parentPath(file);
int parentlen = strlen(parent);
char * erroredFile = NULL;
strcpy(rfile,file);
strcat(rfile,".");
strcat(rfile,PLAYLIST_FILE_SUFFIX);
if((actualFile = rpp2app(rfile)) && isPlaylist(actualFile)) free(rfile);
else {
free(rfile);
myfprintf(fp,"%s playlist \"%s\" not found\n",
COMMAND_RESPOND_ERROR,file);
return -1;
}
while(!(fileP = fopen(actualFile,"r")) && errno==EINTR);
if(fileP==NULL) {
myfprintf(fp,"%s Problems opening file \"%s\"\n",
COMMAND_RESPOND_ERROR,file);
return -1;
}
while((s[slength] = fgetc(fileP))!=EOF) {
if(s[slength]=='\n' || s[slength]=='\0') {
s[slength] = '\0';
if(strncmp(s,musicDir,strlen(musicDir))==0) {
strcpy(s,&(s[strlen(musicDir)]));
}
else if(parentlen) {
char * temp = strdup(s);
memset(s,0,MAXPATHLEN+1);
strcpy(s,parent);
strncat(s,"/",MAXPATHLEN-parentlen);
strncat(s,temp,MAXPATHLEN-parentlen-1);
if(strlen(s)>=MAXPATHLEN) {
myfprintf(fp,"%s \"%s\" too long\n",COMMAND_RESPOND_ERROR,temp);
free(temp);
while(fclose(fileP) && errno==EINTR);
if(erroredFile) free(erroredFile);
return -1;
}
free(temp);
}
slength = 0;
if(s[0]==PLAYLIST_COMMENT && !getSong(s)) continue;
if((addToPlaylist(stderr,s))<0) {
if(!erroredFile) erroredFile = strdup(s);
}
}
else if(slength==MAXPATHLEN) {
s[slength] = '\0';
myfprintf(fp,"%s \"%s\" too long\n",COMMAND_RESPOND_ERROR,s);
while(fclose(fileP) && errno==EINTR);
if(erroredFile) free(erroredFile);
return -1;
}
else if(s[slength]!='\r') slength++;
}
while(fclose(fileP) && errno==EINTR);
if(erroredFile) {
fprintf(fp,"%s can't add file \"%s\"\n",COMMAND_RESPOND_ERROR,
erroredFile);
free(erroredFile);
return -1;
}
return 0;
}
int getPlaylistCurrentSong() {
return playlist.order[playlist.current];
}
unsigned long getPlaylistVersion() {
return playlist.version;
}
int getPlaylistLength() {
return playlist.length;
}
int seekSongInPlaylist(FILE * fp, int song, float time) {
int i = song;
if(song<0) {
myfprintf(fp,"%s need integer >= -1\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(!playlist.length) {
myfprintf(fp,"%s playlist is empty\n",COMMAND_RESPOND_ERROR);
return -1;
}
else if(song>=playlist.length) {
myfprintf(fp,"%s song doesn't exist\n",COMMAND_RESPOND_ERROR);
return -1;
}
if(playlist.random) for(i=0;song!=playlist.order[i];i++);
clearPlayerError();
playlist_stopOnError = 1;
playlist_errorCount = 0;
if(playlist_state == PLAYLIST_STATE_PLAY) {
if(playlist.queued>0) {
lockPlaylistInteraction();
clearPlayerQueue();
unlockPlaylistInteraction();
}
}
else if(playPlaylistOrderNumber(fp,i)<0) return -1;
if(playlist.current!=i) if(playPlaylistOrderNumber(fp,i)<0) return -1;
return playerSeek(fp,playlist.songs[playlist.order[i]]->file,time);
}
...@@ -27,16 +27,16 @@ ...@@ -27,16 +27,16 @@
#define PLAYLIST_FILE_SUFFIX "m3u" #define PLAYLIST_FILE_SUFFIX "m3u"
typedef struct _Playlist { void initPlaylist();
Song ** songs;
int length; void finishPlaylist();
int current;
int repeat;
unsigned long version;
} Playlist;
void initPlaylist(); void initPlaylist();
void readPlaylistState();
void savePlaylistState();
int clearPlaylist(FILE * fp); int clearPlaylist(FILE * fp);
int addToPlaylist(FILE * fp, char * file); int addToPlaylist(FILE * fp, char * file);
...@@ -49,11 +49,11 @@ int playlistInfo(FILE * fp, int song); ...@@ -49,11 +49,11 @@ int playlistInfo(FILE * fp, int song);
int stopPlaylist(FILE * fp); int stopPlaylist(FILE * fp);
int playPlaylist(FILE * fp, int song); int playPlaylist(FILE * fp, int song, int stopOnError);
int nextSongInPlaylist(FILE * fp); int nextSongInPlaylist(FILE * fp);
void nextSongInPlaylistIfPlayerStopped(); void syncPlayerAndPlaylist();
int previousSongInPlaylist(FILE * fp); int previousSongInPlaylist(FILE * fp);
...@@ -67,10 +67,28 @@ void deleteASongFromPlaylist(Song * song); ...@@ -67,10 +67,28 @@ void deleteASongFromPlaylist(Song * song);
void deleteSongsFromPlaylist(SongList * songList); void deleteSongsFromPlaylist(SongList * songList);
int moveSongInPlaylist(FILE * fp, int from, int to);
int swapSongsInPlaylist(FILE * fp, int song1, int song2);
int loadPlaylist(FILE * fp, char * file); int loadPlaylist(FILE * fp, char * file);
int getPlaylistRepeatStatus(); int getPlaylistRepeatStatus();
int setPlaylistRepeatStatus(FILE * fp, int status); int setPlaylistRepeatStatus(FILE * fp, int status);
int getPlaylistRandomStatus();
int setPlaylistRandomStatus(FILE * fp, int status);
int getPlaylistCurrentSong();
int getPlaylistLength();
unsigned long getPlaylistVersion();
void playPlaylistIfPlayerStopped();
int seekSongInPlaylist(FILE * fp, int song, float time);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2003 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 "sig_handlers.h"
#include "player.h"
#include "playlist.h"
#include <signal.h>
struct sigaction original_termSa;
void termSigHandler(int signal) {
if(signal==SIGTERM) {
savePlaylistState();
playerKill();
exit(0);
}
}
void usr1SigHandler(int signal) {
}
void initSigHandlers() {
struct sigaction sa;
sa.sa_flags = 0;
sigemptyset(&sa.sa_mask);
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE,&sa,NULL);
sa.sa_handler = usr1SigHandler;
sigaction(SIGUSR1,&sa,NULL);
sa.sa_handler = player_sigHandler;
sigaction(SIGCHLD,&sa,NULL);
sa.sa_handler = termSigHandler;
sigaddset(&sa.sa_mask,SIGTERM);
sigaction(SIGTERM,&sa,&original_termSa);
}
void finishSigHandlers() {
sigaction(SIGTERM,&original_termSa,NULL);
}
void blockSignals() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGCHLD);
sigaddset(&sset,SIGUSR1);
sigprocmask(SIG_BLOCK,&sset,NULL);
}
void unblockSignals() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGCHLD);
sigaddset(&sset,SIGUSR1);
sigprocmask(SIG_UNBLOCK,&sset,NULL);
}
void blockTermSignal() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGTERM);
sigprocmask(SIG_BLOCK,&sset,NULL);
}
void unblockTermSignal() {
sigset_t sset;
sigemptyset(&sset);
sigaddset(&sset,SIGTERM);
sigprocmask(SIG_UNBLOCK,&sset,NULL);
}
/* the Music Player Daemon (MPD)
* (c)2003 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 SIG_HANDLERS_H
#define SIG_HANDLERS_H
void initSigHandlers();
void finishSigHandlers();
void blockSignals();
void unblockSignals();
void blockTermSignal();
void unblockTermSignal();
#endif
...@@ -22,7 +22,7 @@ ...@@ -22,7 +22,7 @@
#include "tables.h" #include "tables.h"
#include "utils.h" #include "utils.h"
#include "tag.h" #include "tag.h"
#include "myfprintf.h" #include "log.h"
#define SONG_KEY "key: " #define SONG_KEY "key: "
#define SONG_FILE "file: " #define SONG_FILE "file: "
...@@ -116,16 +116,16 @@ int printSongInfoFromList(FILE * fp, SongList * list) { ...@@ -116,16 +116,16 @@ int printSongInfoFromList(FILE * fp, SongList * list) {
void writeSongInfoFromList(FILE * fp, SongList * list) { void writeSongInfoFromList(FILE * fp, SongList * list) {
ListNode * tempNode = list->firstNode; ListNode * tempNode = list->firstNode;
fprintf(fp,"%s\n",SONG_BEGIN); myfprintf(fp,"%s\n",SONG_BEGIN);
while(tempNode!=NULL) { while(tempNode!=NULL) {
fprintf(fp,"%s%s\n",SONG_KEY,tempNode->key); myfprintf(fp,"%s%s\n",SONG_KEY,tempNode->key);
printSongInfo(fp,(Song *)tempNode->data); printSongInfo(fp,(Song *)tempNode->data);
fprintf(fp,"%s%li\n",SONG_MTIME,(long)((Song *)tempNode->data)->mtime); myfprintf(fp,"%s%li\n",SONG_MTIME,(long)((Song *)tempNode->data)->mtime);
tempNode = tempNode->nextNode; tempNode = tempNode->nextNode;
} }
fprintf(fp,"%s\n",SONG_END); myfprintf(fp,"%s\n",SONG_END);
} }
void readSongInfoIntoList(FILE * fp, SongList * list) { void readSongInfoIntoList(FILE * fp, SongList * list) {
...@@ -148,7 +148,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) { ...@@ -148,7 +148,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
} }
else if(0==strncmp(SONG_FILE,buffer,strlen(SONG_FILE))) { else if(0==strncmp(SONG_FILE,buffer,strlen(SONG_FILE))) {
if(!song || song->file) { if(!song || song->file) {
fprintf(stderr,"Problems reading song info\n"); ERROR0("Problems reading song info\n");
exit(-1); exit(-1);
} }
song->file = strdup(&(buffer[strlen(SONG_FILE)])); song->file = strdup(&(buffer[strlen(SONG_FILE)]));
...@@ -173,7 +173,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) { ...@@ -173,7 +173,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
song->mtime = atoi(&(buffer[strlen(SONG_TITLE)])); song->mtime = atoi(&(buffer[strlen(SONG_TITLE)]));
} }
else { else {
fprintf(stderr,"unknown line in db: %s\n",buffer); ERROR1("unknown line in db: %s\n",buffer);
exit(-1); exit(-1);
} }
} }
......
...@@ -28,8 +28,8 @@ Stats stats; ...@@ -28,8 +28,8 @@ Stats stats;
void initStats() { void initStats() {
stats.daemonStart = time(NULL); stats.daemonStart = time(NULL);
stats.playTime = 0; /*stats.playTime = 0;
stats.songsPlayed = 0; stats.songsPlayed = 0;*/
} }
int printStats(FILE * fp) { int printStats(FILE * fp) {
...@@ -37,8 +37,8 @@ int printStats(FILE * fp) { ...@@ -37,8 +37,8 @@ int printStats(FILE * fp) {
myfprintf(fp,"albums: %li\n",numberOfAlbums()); myfprintf(fp,"albums: %li\n",numberOfAlbums());
myfprintf(fp,"songs: %li\n",numberOfSongs()); myfprintf(fp,"songs: %li\n",numberOfSongs());
myfprintf(fp,"uptime: %li\n",time(NULL)-stats.daemonStart); myfprintf(fp,"uptime: %li\n",time(NULL)-stats.daemonStart);
myfprintf(fp,"playtime: %li\n",stats.playTime); /*myfprintf(fp,"playtime: %li\n",stats.playTime);
myfprintf(fp,"songs_played: %li\n",stats.songsPlayed); myfprintf(fp,"songs_played: %li\n",stats.songsPlayed);*/
myfprintf(fp,"db_update: %li\n",getDbModTime()); myfprintf(fp,"db_update: %li\n",getDbModTime());
return 0; return 0;
} }
...@@ -23,8 +23,8 @@ ...@@ -23,8 +23,8 @@
typedef struct _Stats { typedef struct _Stats {
unsigned long daemonStart; unsigned long daemonStart;
unsigned long playTime; /*unsigned long playTime;
unsigned long songsPlayed; unsigned long songsPlayed;*/
} Stats; } Stats;
extern Stats stats; extern Stats stats;
......
...@@ -134,7 +134,7 @@ int findAndPrintSongsInTable(FILE * fp, char * table, char * find) { ...@@ -134,7 +134,7 @@ int findAndPrintSongsInTable(FILE * fp, char * table, char * find) {
return findAndPrintSongsInArtistTable(fp,find); return findAndPrintSongsInArtistTable(fp,find);
} }
myfprintf(fp,"%s unkown table\n",COMMAND_RESPOND_ERROR); myfprintf(fp,"%s unknown table\n",COMMAND_RESPOND_ERROR);
return -1; return -1;
} }
...@@ -254,7 +254,7 @@ int searchForSongsInTable(FILE * fp, char * table, char * search) { ...@@ -254,7 +254,7 @@ int searchForSongsInTable(FILE * fp, char * table, char * search) {
return searchForSongsInSongTableByFilename(fp,search); return searchForSongsInSongTableByFilename(fp,search);
} }
myfprintf(fp,"%s unkown table\n",COMMAND_RESPOND_ERROR); myfprintf(fp,"%s unknown table\n",COMMAND_RESPOND_ERROR);
return -1; return -1;
} }
......
...@@ -19,12 +19,14 @@ ...@@ -19,12 +19,14 @@
#include "tag.h" #include "tag.h"
#include "path.h" #include "path.h"
#include "myfprintf.h" #include "myfprintf.h"
#include "sig_handlers.h"
#include <sys/stat.h> #include <sys/stat.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
#ifdef HAVE_OGG #ifdef HAVE_OGG
#include <vorbis/vorbisfile.h> #include <vorbis/vorbisfile.h>
#endif #endif
...@@ -79,11 +81,19 @@ MpdTag * id3Dup(char * filename) { ...@@ -79,11 +81,19 @@ MpdTag * id3Dup(char * filename) {
struct id3_tag * tag; struct id3_tag * tag;
char * str; char * str;
blockSignals();
file = id3_file_open(rmp2amp(filename),ID3_FILE_MODE_READONLY); file = id3_file_open(rmp2amp(filename),ID3_FILE_MODE_READONLY);
if(!file) return NULL; if(!file) {
unblockSignals();
return NULL;
}
tag = id3_file_tag(file); tag = id3_file_tag(file);
if(!tag) return NULL; if(!tag) {
id3_file_close(file);
unblockSignals();
return NULL;
}
str = getID3Info(tag,ID3_FRAME_ARTIST); str = getID3Info(tag,ID3_FRAME_ARTIST);
if(str) { if(str) {
...@@ -117,6 +127,7 @@ MpdTag * id3Dup(char * filename) { ...@@ -117,6 +127,7 @@ MpdTag * id3Dup(char * filename) {
if(!ret->title) ret->title = strdup(""); if(!ret->title) ret->title = strdup("");
if(!ret->track) ret->track = strdup(""); if(!ret->track) ret->track = strdup("");
} }
unblockSignals();
#endif #endif
return ret; return ret;
} }
...@@ -131,8 +142,14 @@ MpdTag * oggCommentDup(char * file) { ...@@ -131,8 +142,14 @@ MpdTag * oggCommentDup(char * file) {
char * s1; char * s1;
char * s2; char * s2;
if(!(fp = fopen(rmp2amp(file),"r"))) return NULL; while(!(fp = fopen(rmp2amp(file),"r")) && errno==EINTR);
if(ov_open(fp,&vf,NULL,0)<0) return NULL; if(!fp) return NULL;
blockSignals();
if(ov_open(fp,&vf,NULL,0)<0) {
unblockSignals();
while(fclose(fp) && errno==EINTR);
return NULL;
}
comments = ov_comment(&vf,-1)->user_comments; comments = ov_comment(&vf,-1)->user_comments;
...@@ -169,6 +186,7 @@ MpdTag * oggCommentDup(char * file) { ...@@ -169,6 +186,7 @@ MpdTag * oggCommentDup(char * file) {
if(!ret->track) ret->track = strdup(""); if(!ret->track) ret->track = strdup("");
} }
unblockSignals();
return ret; return ret;
} }
#endif #endif
...@@ -182,9 +200,11 @@ MpdTag * flacVorbisCommentDup(char * file) { ...@@ -182,9 +200,11 @@ MpdTag * flacVorbisCommentDup(char * file) {
int offset; int offset;
int len, pos; int len, pos;
blockSignals();
it = FLAC__metadata_simple_iterator_new(); it = FLAC__metadata_simple_iterator_new();
if(!FLAC__metadata_simple_iterator_init(it,rmp2amp(file),1,0)) { if(!FLAC__metadata_simple_iterator_init(it,rmp2amp(file),1,0)) {
FLAC__metadata_simple_iterator_delete(it); FLAC__metadata_simple_iterator_delete(it);
unblockSignals();
return ret; return ret;
} }
...@@ -249,6 +269,7 @@ MpdTag * flacVorbisCommentDup(char * file) { ...@@ -249,6 +269,7 @@ MpdTag * flacVorbisCommentDup(char * file) {
if(block) FLAC__metadata_object_delete(block); if(block) FLAC__metadata_object_delete(block);
FLAC__metadata_simple_iterator_delete(it); FLAC__metadata_simple_iterator_delete(it);
unblockSignals();
return ret; return ret;
} }
#endif #endif
......
/* the Music Player Daemon (MPD)
* (c)2003 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 "volume.h"
#include "command.h"
#include "conf.h"
#include "log.h"
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <errno.h>
#ifndef NO_OSS_MIXER
#include <sys/soundcard.h>
#endif
#ifdef HAVE_ALSA
#include <alsa/asoundlib.h>
#endif
#define VOLUME_MIXER_TYPE_NULL 0
#define VOLUME_MIXER_TYPE_OSS 1
#define VOLUME_MIXER_TYPE_ALSA 2
#define VOLUME_MIXER_NULL_DEFAULT ""
#define VOLUME_MIXER_OSS_DEFAULT "/dev/mixer"
#define VOLUME_MIXER_ALSA_DEFAULT "default"
int volume_mixerType = VOLUME_MIXER_TYPE_NULL;
char * volume_mixerDevice;
#ifndef NO_OSSMIXER
int volume_ossFd;
#endif
#ifdef HAVE_ALSA
snd_mixer_t * volume_alsaMixerHandle = NULL;
snd_mixer_elem_t * volume_alsaElem;
long volume_alsaMin;
long volume_alsaMax;
#endif
#ifndef NO_OSS_MIXER
int prepOssMixer(char * device) {
if((volume_ossFd = open(device,O_RDONLY))<0) {
ERROR1("unable to open oss mixer \"%s\"\n",device);
return -1;
}
return 0;
}
void closeOssMixer() {
close(volume_ossFd);
}
int getOssVolumeLevel() {
int left, right, level;
if(ioctl(volume_ossFd,MIXER_READ(SOUND_MIXER_VOLUME),&level) < 0) {
while(close(volume_ossFd)<0 && errno==EINTR);
ERROR0("unable to read volume\n");
return -1;
}
left = level & 0xff;
right = (level & 0xff00) >> 8;
if(left!=right) {
ERROR2("volume for left and right is not the same, \"%i\" and "
"\"%i\"\n",left,right);
}
return left;
}
int changeOssVolumeLevel(FILE * fp, int change) {
int current;
int new;
int level;
if((current = getOssVolumeLevel()) < 0) {
myfprintf(fp,"%s problem getting current volume\n",COMMAND_RESPOND_ERROR);
return -1;
}
new = current+change;
if(new<0) new = 0;
else if(new>100) new = 100;
level = (new << 8) + new;
if(ioctl(volume_ossFd,MIXER_WRITE(SOUND_MIXER_VOLUME),&level) < 0) {
myfprintf(fp,"%s problems setting volume\n",COMMAND_RESPOND_ERROR);
return -1;
}
return 0;
}
#endif
#ifdef HAVE_ALSA
int prepAlsaMixer(char * card) {
int err;
if((err = snd_mixer_open(&volume_alsaMixerHandle,0))<0) {
ERROR1("problems opening alsa mixer: %s\n",snd_strerror(err));
return -1;
}
if((err = snd_mixer_attach(volume_alsaMixerHandle,card))<0) {
snd_mixer_close(volume_alsaMixerHandle);
ERROR1("problems problems attaching alsa mixer: %s\n",
snd_strerror(err));
return -1;
}
if((err = snd_mixer_selem_register(volume_alsaMixerHandle,NULL,NULL))<0) {
snd_mixer_close(volume_alsaMixerHandle);
ERROR1("problems snd_mixer_selem_register'ing: %s\n",
snd_strerror(err));
return -1;
}
if((err = snd_mixer_load(volume_alsaMixerHandle))<0) {
snd_mixer_close(volume_alsaMixerHandle);
ERROR1("problems snd_mixer_selem_register'ing: %s\n",
snd_strerror(err));
return -1;
}
volume_alsaElem = snd_mixer_first_elem(volume_alsaMixerHandle);
if(snd_mixer_elem_get_type(volume_alsaElem)==SND_MIXER_ELEM_SIMPLE) {
snd_mixer_selem_get_playback_volume_range(volume_alsaElem,
&volume_alsaMin,&volume_alsaMax);
return 0;
}
snd_mixer_close(volume_alsaMixerHandle);
return -1;
}
void closeAlsaMixer() {
snd_mixer_close(volume_alsaMixerHandle);
}
int getAlsaVolumeLevel() {
int ret;
long level;
long max = volume_alsaMax;
long min = volume_alsaMin;
int err;
if((err = snd_mixer_selem_get_playback_volume(volume_alsaElem,
SND_MIXER_SCHN_FRONT_LEFT,&level))<0) {
ERROR1("problems getting alsa volume: %s\n",snd_strerror(err));
return -1;
}
snd_mixer_selem_get_playback_volume(volume_alsaElem,
SND_MIXER_SCHN_FRONT_LEFT,&level);
ret = (int)(100*(((float)(level-min))/(max-min))+0.5);
return ret;
}
int changeAlsaVolumeLevel(FILE * fp, int change) {
float vol;
long level;
long max = volume_alsaMax;
long min = volume_alsaMin;
int err;
if((err = snd_mixer_selem_get_playback_volume(volume_alsaElem,
SND_MIXER_SCHN_FRONT_LEFT,&level))<0) {
myfprintf(fp,"%s problems getting volume\n",
COMMAND_RESPOND_ERROR);
ERROR1("problems getting alsa volume: %s\n",snd_strerror(err));
return -1;
}
vol = 100.0*(((float)(level-min))/(max-min));
vol+=change;
level = (long)(((vol/100.0)*(max-min)+min)+0.5);
level = level>max?max:level;
level = level<min?min:level;
if((err = snd_mixer_selem_set_playback_volume_all(
volume_alsaElem,level))<0) {
myfprintf(fp,"%s problems setting volume\n",
COMMAND_RESPOND_ERROR);
ERROR1("problems setting alsa volume: %s\n",snd_strerror(err));
return -1;
}
return 0;
}
#endif
int prepMixer(char * device) {
switch(volume_mixerType) {
#ifdef HAVE_ALSA
case VOLUME_MIXER_TYPE_ALSA:
return prepAlsaMixer(device);
#endif
#ifndef NO_OSS_MIXER
case VOLUME_MIXER_TYPE_OSS:
return prepOssMixer(device);
#endif
}
return 0;
}
void finishVolume() {
switch(volume_mixerType) {
#ifdef HAVE_ALSA
case VOLUME_MIXER_TYPE_ALSA:
closeAlsaMixer();
break;
#endif
#ifndef NO_OSS_MIXER
case VOLUME_MIXER_TYPE_OSS:
closeOssMixer();
break;
#endif
}
}
void initVolume() {
if(0);
#ifdef HAVE_ALSA
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_ALSA)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_ALSA;
volume_mixerDevice = VOLUME_MIXER_ALSA_DEFAULT;
}
#endif
#ifndef NO_OSS_MIXER
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_OSS)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_OSS;
volume_mixerDevice = VOLUME_MIXER_OSS_DEFAULT;
}
#endif
else if(strcmp((getConf())[CONF_MIXER_TYPE],VOLUME_MIXER_NULL)==0) {
volume_mixerType = VOLUME_MIXER_TYPE_NULL;
volume_mixerDevice = VOLUME_MIXER_NULL_DEFAULT;
}
else {
ERROR1("unknown mixer type: %s\n",(getConf())[CONF_MIXER_TYPE]);
exit(-1);
}
if(strlen((getConf())[CONF_MIXER_DEVICE])) {
volume_mixerDevice = (getConf())[CONF_MIXER_DEVICE];
}
}
void openVolumeDevice() {
if(prepMixer(volume_mixerDevice)<0) {
ERROR0("volume support will be disabled\n");
volume_mixerType = VOLUME_MIXER_TYPE_NULL;
}
}
int getVolumeLevel() {
switch(volume_mixerType) {
#ifdef HAVE_ALSA
case VOLUME_MIXER_TYPE_ALSA:
return getAlsaVolumeLevel();
#endif
#ifndef NO_OSS_MIXER
case VOLUME_MIXER_TYPE_OSS:
return getOssVolumeLevel();
#endif
default:
return -1;
}
}
int changeVolumeLevel(FILE * fp, int change) {
switch(volume_mixerType) {
#ifdef HAVE_ALSA
case VOLUME_MIXER_TYPE_ALSA:
return changeAlsaVolumeLevel(fp,change);
#endif
#ifndef NO_OSS_MIXER
case VOLUME_MIXER_TYPE_OSS:
return changeOssVolumeLevel(fp,change);
#endif
default:
myfprintf(fp,"%s no volume support!\n",COMMAND_RESPOND_ERROR);
return -1;
}
}
...@@ -21,6 +21,16 @@ ...@@ -21,6 +21,16 @@
#include <stdio.h> #include <stdio.h>
#define VOLUME_MIXER_OSS "oss"
#define VOLUME_MIXER_ALSA "alsa"
#define VOLUME_MIXER_NULL "null"
void initVolume();
void openVolumeDevice();
void finishVolume();
int getVolumeLevel(); int getVolumeLevel();
int changeVolumeLevel(FILE * fp, int change); int changeVolumeLevel(FILE * fp, int change);
......
/* the Music Player Daemon (MPD)
* (c)2003 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 "volume.h"
#include "command.h"
#include "conf.h"
#include "myfprintf.h"
#include <stdlib.h>
#include <unistd.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#ifndef NO_OSS_MIXER
#include <sys/soundcard.h>
#endif
int getVolumeLevel() {
#ifndef NO_OSS_MIXER
char * device = (getConf())[CONF_MIXER_DEVICE];
int fd;
int left, right, level;
if((fd = open(device,O_RDONLY))<0) {
fprintf(stderr, "%s unable to mixer \"%s\"\n",COMMAND_RESPOND_ERROR,device);
return -1;
}
if(ioctl(fd,MIXER_READ(SOUND_MIXER_VOLUME),&level) < 0) {
close(fd);
fprintf(stderr,"%s unable to read volume\n",COMMAND_RESPOND_ERROR);
return -1;
}
close(fd);
left = level & 0xff;
right = (level & 0xff00) >> 8;
if(left!=right) {
fprintf(stderr,"%s volume for left and right is not the same, \"%i\" and \"%i\"\n",COMMAND_RESPOND_ERROR,left,right);
}
return left;
#else
return -1;
#endif
}
int changeVolumeLevel(FILE * fp, int change) {
#ifndef NO_OSS_MIXER
int current;
int new;
int level;
int fd;
char * device = (getConf())[CONF_MIXER_DEVICE];
if((current = getVolumeLevel()) < 0) {
myfprintf(fp,"%s problem getting current volume\n",COMMAND_RESPOND_ERROR);
return -1;
}
new = current+change;
if(new<0) new = 0;
else if(new>100) new = 100;
level = (new << 8) + new;
if((fd = open(device,O_RDONLY)) < 0) {
fprintf(fp,"%s problems opening mixer device \"%s\"\n",COMMAND_RESPOND_ERROR,device);
return -1;
}
if(ioctl(fd,MIXER_WRITE(SOUND_MIXER_VOLUME),&level) < 0) {
fprintf(fp,"%s problems setting volume\n",COMMAND_RESPOND_ERROR);
close(fd);
return -1;
}
close(fd);
return 0;
#else
fprintf(fp,"%s no volume support!\n",COMMAND_RESPOND_ERROR);
return -1;
#endif
}
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