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)
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().
......
......@@ -6,20 +6,20 @@ Requirements
libao - http://www.vorbis.com/download_unix.psp
(This comes with most/all distributions. Make sure you have both
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
(This comes with all distributions. Make sure you have bot the zlib libs
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
--------
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
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).
Flac - http://flac.sf.net
......@@ -33,7 +33,7 @@ Get the latest release from of MPD from http://www.musicpd.org
Compile
-------
1) unzip and untar the argchive
1) unzip and untar the archive
$ tar zxvf mpd-x.x.x.tar.gz
......@@ -80,6 +80,8 @@ run mpd like this:
$ mpd <config file>
(if no config file is specified, mpd's looks for ~/.mpdconf then /etc/mpd.conf)
an example would be:
$ mpd playlists/.mpdconf
......@@ -92,4 +94,6 @@ Using MPD
You can download a web interface (phpMp) to MPD at
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).
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
man_MANS = mpd.1
pkgdata_DATA =
SUBDIRS = src doc debian
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING
EXTRA_DIST = mpdconf.example COMMANDS COPYING $(pkgdata_DATA) $(man_MANS) $(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)
EXTRA_DIST = COPYING $(doc_DATA)
......@@ -68,14 +68,21 @@ 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@
......@@ -92,6 +99,7 @@ OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
VORBISENC_LIBS = @VORBISENC_LIBS@
......@@ -101,79 +109,16 @@ VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR)
man_MANS = mpd.1
pkgdata_DATA =
SUBDIRS = src doc debian
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING
EXTRA_DIST = mpdconf.example COMMANDS COPYING $(pkgdata_DATA) $(man_MANS) $(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)
EXTRA_DIST = COPYING $(doc_DATA)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
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) \
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)
DIST_SOURCES =
DATA = $(doc_DATA)
RECURSIVE_TARGETS = info-recursive dvi-recursive install-info-recursive \
......@@ -184,12 +129,9 @@ DIST_COMMON = README COPYING ChangeLog INSTALL Makefile.am Makefile.in \
TODO aclocal.m4 config.guess config.sub configure configure.in \
depcomp install-sh ltmain.sh missing mkinstalldirs
DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(mpd_SOURCES)
all: all-recursive
.SUFFIXES:
.SUFFIXES: .c .lo .o .obj
am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
configure.lineno
......@@ -206,92 +148,6 @@ $(srcdir)/configure: $(srcdir)/configure.in $(ACLOCAL_M4) $(CONFIGURE_DEPENDENC
$(ACLOCAL_M4): configure.in
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:
-rm -f *.lo
......@@ -302,49 +158,6 @@ clean-libtool:
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)
......@@ -363,24 +176,6 @@ uninstall-docDATA:
echo " rm -f $(DESTDIR)$(docdir)/$$f"; \
rm -f $(DESTDIR)$(docdir)/$$f; \
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
# into them and run `make' without going through this Makefile.
......@@ -580,10 +375,10 @@ distcleancheck: distclean
exit 1; } >&2
check-am: all-am
check: check-recursive
all-am: Makefile $(PROGRAMS) $(MANS) $(DATA)
all-am: Makefile $(DATA)
installdirs: installdirs-recursive
installdirs-am:
$(mkinstalldirs) $(DESTDIR)$(bindir) $(DESTDIR)$(man1dir) $(DESTDIR)$(docdir) $(DESTDIR)$(pkgdatadir)
$(mkinstalldirs) $(DESTDIR)$(docdir)
install: install-recursive
install-exec: install-exec-recursive
......@@ -611,12 +406,12 @@ maintainer-clean-generic:
@echo "it deletes files that may require special tools to rebuild."
clean: clean-recursive
clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
clean-am: clean-generic clean-libtool mostlyclean-am
distclean: distclean-recursive
-rm -f $(am__CONFIG_DISTCLEAN_FILES)
distclean-am: clean-am distclean-compile distclean-depend \
distclean-generic distclean-libtool distclean-tags
distclean-am: clean-am distclean-generic distclean-libtool \
distclean-tags
dvi: dvi-recursive
......@@ -626,13 +421,13 @@ info: info-recursive
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-man: install-man1
install-man:
installcheck-am:
......@@ -643,35 +438,28 @@ maintainer-clean-am: distclean-am maintainer-clean-generic
mostlyclean: mostlyclean-recursive
mostlyclean-am: mostlyclean-compile mostlyclean-generic \
mostlyclean-libtool
mostlyclean-am: mostlyclean-generic mostlyclean-libtool
uninstall-am: uninstall-binPROGRAMS uninstall-docDATA uninstall-info-am \
uninstall-man uninstall-pkgdataDATA
uninstall-am: uninstall-docDATA uninstall-info-am
uninstall-info: uninstall-info-recursive
uninstall-man: uninstall-man1
.PHONY: $(RECURSIVE_TARGETS) GTAGS all all-am check check-am clean \
clean-binPROGRAMS clean-generic clean-libtool clean-recursive \
dist dist-all dist-gzip distcheck distclean distclean-compile \
distclean-depend distclean-generic distclean-libtool \
distclean-recursive distclean-tags distcleancheck distdir dvi \
dvi-am dvi-recursive info info-am info-recursive install \
install-am install-binPROGRAMS install-data install-data-am \
clean-generic clean-libtool clean-recursive dist dist-all \
dist-gzip distcheck distclean distclean-generic \
distclean-libtool distclean-recursive distclean-tags \
distcleancheck distdir dvi dvi-am dvi-recursive info info-am \
info-recursive install install-am install-data install-data-am \
install-data-recursive install-docDATA install-exec \
install-exec-am install-exec-recursive install-info \
install-info-am install-info-recursive install-man install-man1 \
install-pkgdataDATA 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-docDATA uninstall-info-am \
uninstall-info-recursive uninstall-man uninstall-man1 \
uninstall-pkgdataDATA uninstall-recursive
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-generic \
mostlyclean-libtool mostlyclean-recursive tags tags-recursive \
uninstall uninstall-am uninstall-docDATA 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.
......
0.10.0
------
1) store song times (possibly after playing)
2) seeking
3) set flags (such as BAD MP3)
possibly:
---------
reference songs by an id #
spawn a seperate process for db updates, that pipes updates through a socket
to the main process
2) possibly, crossfading
3) resample in software for sound cards that support a limited range of
sampling rate.
4) Password protection
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".
Upgrading from 0.5.x to 0.6.x
-----------------------------
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
interface) to add your ogg's to MPD's list of available music.
If you compiled with "make ogg", just use "update" (available via the phpMp
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)
AM_INIT_AUTOMAKE(mpd, 0.8.7)
AC_INIT(src/main.c)
AM_INIT_AUTOMAKE(mpd, 0.9.0)
AC_PROG_CC
AC_PROG_INSTALL
......@@ -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(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!!!))
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=""
if test x$enable_id3 = xyes; then
if test x$use_mpd_id3tag = xyes; then
ID3_SUBDIR="libid3tag"
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
CFLAGS="$CFLAGS -lz"
AC_CHECK_LIB(id3tag,id3_file_open,[ID3_LIB="-lid3tag -lz";
CFLAGS="$CFLAGS $ID3TAG_CFLAGS $ID3TAG_LIBS"
AC_CHECK_LIB(id3tag,id3_file_open,[ID3_LIB="$ID3TAG_LIBS";
MPD_CFLAGS="$MPD_CFLAGS $ID3TAG_CFLAGS";
use_libid3tag=yes],
[use_libid3tag=no;use_mpd_id3tag=yes])
CFLAGS=$oldcflags
......@@ -46,7 +111,7 @@ if test x$enable_id3 = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_ID3TAG"
ID3_LIB="libid3tag/libid3tag.la"
ID3_SUBDIR="libid3tag"
AC_CONFIG_SUBDIRS(libid3tag)
AC_CONFIG_SUBDIRS(src/libid3tag)
fi
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_ID3TAG"
fi
......@@ -57,24 +122,94 @@ if test x$enable_mp3 = xyes; then
if test x$use_mpd_mad = xyes; then
MAD_SUBDIR="libmad"
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])
fi
if test x$use_mpd_mad = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DUSE_MPD_MAD"
MAD_LIB="libmad/libmad.la"
MAD_SUBDIR="libmad"
AC_CONFIG_SUBDIRS(libmad)
AC_CONFIG_SUBDIRS(src/libmad)
fi
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_MAD"
fi
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
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
if test x$enable_ogg = xyes; then
......@@ -107,4 +242,4 @@ if test x$enable_flac = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -DHAVE_FLAC"
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> ...
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.
Commands:
......@@ -31,7 +31,7 @@ clearerror
(this is also accomplished by any command that starts playback)
close
close the connection with the mpd
close the connection with the MPD
delete <int song>
delete _song_ from playlist
......@@ -42,12 +42,12 @@ find <string type> <string what>
_what_ is what to find
kill
kill mpd
kill MPD
list <string type> <string arg1>
list all tags of _type_
_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
arg1
......@@ -66,6 +66,9 @@ ls <string directory>
lsinfo <string directory>
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
plays next song in playlist
......@@ -73,7 +76,7 @@ pause
pause/resume playing
play <int song>
begin playling playlist at song number _song_, _song_ is optiional
begin playing playlist at song number _song_, _song_ is optional
playlist
displays the current playlist
......@@ -85,19 +88,23 @@ playlistinfo
previous
plays previous song in playlist
repeat <int state>
set repeat state to _state_, _state_ should be 0 or 1
rm <string name>
removes the playlist <name>.m3u from the playlist directory
save <string name>
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>
same as "find" but searches for any song that contain _what_
search is not case sensitive
seek <int song> <int time>
seeks to the position _time_ (in seconds) of entry _song_ in the
playlist
shuffle
shuffles the current playlist
......@@ -107,15 +114,16 @@ stats
albums: number of albums
songs: number of songs
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
songs_played: total number of songs played
status
reports current status of player, and volume level.
volume: (0-100).
repat: (0 or 1)
repeat: (0 or 1)
playlist: (31-bit unsigned integer, the playlist version number)
playlistlength: (integer, the length of the playlist)
state: ("play", "stop", or "pause")
song: (current song playing/paused, playlist song number)
time: <int elapsed>:<time total> (of current playing/paused song)
......@@ -124,6 +132,9 @@ status
stop
stop playing
swap <int song1> <int song2>
swap positions of _song1_ and _song2_
update
searches mp3 directory for new music and removes old music from the db
......@@ -133,7 +144,7 @@ volume <int change>
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:
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"
error_file "/home/shank/mpd.error"
# optional
connection_timeout "60"
mixer_type "oss"
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"
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_output_buffer_size "2048"
ao_driver "oss"
ao_driver_options "dsp=/dev/dsp"
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"
/* 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 @@
#include "audio.h"
#include "conf.h"
#include "log.h"
#include "sig_handlers.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
int audio_ao_driver_id;
ao_option * audio_ao_options;
AudioFormat audio_format;
ao_device * audio_device = NULL;
void initAudioDriver() {
ao_info * ai;
char * dup;
......@@ -43,13 +50,13 @@ void initAudioDriver() {
}
else if((audio_ao_driver_id =
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]);
exit(-1);
}
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);
}
......@@ -61,27 +68,26 @@ void initAudioDriver() {
stk2 = NULL;
key = strtok_r(n1,"=",&stk2);
if(!key) {
fprintf(stderr,"problems parsing "
ERROR1("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(-1);
}
/*found = 0;
for(i=0;i<ai->option_count;i++) {
printf("option: %s\n",ai->options[i]);
if(strcmp(ai->options[i],key)==0) {
found = 1;
break;
}
}
if(!found) {
fprintf(stderr,"\"%s\" is not an option for "
ERROR2("\"%s\" is not an option for "
"\"%s\" ao driver\n",key,
ai->short_name);
exit(-1);
}*/
value = strtok_r(NULL,"",&stk2);
if(!value) {
fprintf(stderr,"problems parsing "
ERROR1("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(-1);
}
......@@ -90,33 +96,75 @@ void initAudioDriver() {
}
}
free(dup);
ao_shutdown();
}
void finishAudioDriver() {
ao_free_options(audio_ao_options);
ao_shutdown();
}
void initAudio() {
ao_initialize();
int initAudio(AudioFormat * audioFormat) {
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() {
ao_shutdown();
if(audio_device) {
blockSignals();
ao_close(audio_device);
audio_device = NULL;
unblockSignals();
}
}
void audioError() {
fprintf(stderr,"Error opening audio device\n");
ERROR0("Error opening audio device\n");
if(errno==AO_ENOTLIVE) {
fprintf(stderr,"not a live ao device\n");
ERROR0("not a live ao device\n");
}
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) {
fprintf(stderr,"bad driver option\n");
ERROR0("bad driver option\n");
}
perror("ao error");
fflush(stderr);
}
......@@ -19,11 +19,17 @@
#ifndef AUDIO_H
#define AUDIO_H
#define AUDIO_AO_DRIVER_DEFAULT "default"
#include <stdio.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 ao_option * audio_ao_options;
......@@ -31,7 +37,9 @@ void initAudioDriver();
void finishAudioDriver();
void initAudio();
int initAudio(AudioFormat * audioFormat);
void playAudio(char * playChunk,int size);
void finishAudio();
......
......@@ -56,20 +56,24 @@
#define COMMAND_LISTALL "listall"
#define COMMAND_VOLUME "volume"
#define COMMAND_REPEAT "repeat"
#define COMMAND_RANDOM "random"
#define COMMAND_STATS "stats"
#define COMMAND_CLEAR_ERROR "clearerror"
#define COMMAND_LIST "list"
#define COMMAND_MOVE "move"
#define COMMAND_SWAP "swap"
#define COMMAND_SEEK "seek"
#define COMMAND_STATUS_VOLUME "volume"
#define COMMAND_STATUS_STATE "state"
#define COMMAND_STATUS_REPEAT "repeat"
#define COMMAND_STATUS_RANDOM "random"
#define COMMAND_STATUS_PLAYLIST "playlist"
#define COMMAND_STATUS_PLAYLIST_LENGTH "playlistlength"
#define COMMAND_STATUS_SONG "song"
#define COMMAND_STATUS_TIME "time"
#define COMMAND_STATUS_ERROR "error"
extern Playlist playlist;
int commandStatus(FILE * fp,int argArrayLength, char ** argArray) {
char * state = NULL;
if(argArrayLength!=1) {
......@@ -77,6 +81,7 @@ int commandStatus(FILE * fp,int argArrayLength, char ** argArray) {
return -1;
}
playPlaylistIfPlayerStopped();
switch(getPlayerState()) {
case PLAYER_STATE_STOP:
state = strdup(COMMAND_STOP);
......@@ -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_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);
if(getPlayerState()>0) {
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,playlist.current);
if(getPlayerState()!=PLAYER_STATE_STOP) {
myfprintf(fp,"%s: %i\n",COMMAND_STATUS_SONG,getPlaylistCurrentSong());
myfprintf(fp,"%s: %i:%i\n",COMMAND_STATUS_TIME,getPlayerElapsedTime(),getPlayerTotalTime());
}
if(strlen(getPlayerError())) {
myfprintf(fp,"%s: %s\n",COMMAND_STATUS_ERROR,getPlayerError());
if(getPlayerError()!=PLAYER_ERROR_NOERROR) {
myfprintf(fp,"%s: %s\n",COMMAND_STATUS_ERROR,getPlayerErrorStr());
}
free(state);
......@@ -114,7 +121,7 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
if(0==strcmp(argArray[0],COMMAND_PLAY)) {
int song = 0;
int song = -1;
char * test;
if(argArrayLength>2) {
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) {
return -1;
}
}
return playPlaylist(fp,song);
return playPlaylist(fp,song,1);
}
else if(0==strcmp(argArray[0],COMMAND_STOP)) {
if(argArrayLength!=1) {
......@@ -160,42 +167,18 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
return addToPlaylist(fp,argArray[1]);
}
else if(0==strcmp(argArray[0],COMMAND_SAVE)) {
char * file;
int ret;
if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
if(strstr(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;
return savePlaylist(fp,argArray[1]);
}
else if(0==strcmp(argArray[0],COMMAND_RM)) {
char * file;
int ret;
if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
if(strstr(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;
return deletePlaylist(fp,argArray[1]);
}
else if(0==strcmp(argArray[0],COMMAND_DELETE)) {
int song;
......@@ -211,6 +194,72 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
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)) {
int change;
char * test;
......@@ -239,6 +288,20 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
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)) {
int song = -1;
char * test;
......@@ -277,19 +340,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
return clearPlaylist(fp);
}
else if(0==strcmp(argArray[0],COMMAND_LOAD)) {
char * file;
int ret = 0;
if(argArrayLength!=2) {
myfprintf(fp,"%s wrong number of arguments for \"%s\"\n",COMMAND_RESPOND_ERROR,argArray[0]);
return -1;
}
file = malloc(strlen(playlistDir)+strlen(argArray[1])+strlen(PLAYLIST_FILE_SUFFIX)+2);
strcpy(file,playlistDir);
strcat(file,argArray[1]);
strcat(file,".");
if(loadPlaylist(fp,strcat(file,PLAYLIST_FILE_SUFFIX))<0) ret=-1;
free(file);
return ret;
return loadPlaylist(fp,argArray[1]);
}
else if(0==strcmp(argArray[0],COMMAND_LS)) {
if(argArrayLength>2) {
......@@ -298,10 +353,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
if(argArrayLength==1) {
if(ls(fp,NULL)<0) return -1;
else return lsPlaylists(fp);
else return lsPlaylists(fp,"");
}
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)) {
......@@ -311,10 +367,11 @@ int processCommand(FILE * fp, int argArrayLength, char ** argArray) {
}
if(argArrayLength==1) {
if(printDirectoryInfo(fp,NULL)<0) return -1;
else return lsPlaylists(fp);
else return lsPlaylists(fp,"");
}
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)) {
......
......@@ -18,9 +18,12 @@
#include "conf.h"
#include "log.h"
#include "utils.h"
#include "buffer2array.h"
#include "audio.h"
#include "volume.h"
#include <sys/param.h>
#include <stdio.h>
......@@ -31,22 +34,35 @@
#define CONF_COMMENT '#'
#define CONF_NUMBER_OF_PARAMS 17
#define CONF_NUMBER_OF_PATHS 4
#define CONF_NUMBER_OF_PARAMS 21
#define CONF_NUMBER_OF_PATHS 6
#define CONF_NUMBER_OF_REQUIRED 5
#define CONF_CONNECTION_TIMEOUT_DEFAULT "60"
#define CONF_MIXER_DEVICE_DEFAULT "/dev/mixer"
#define CONF_MAX_CONNECTIONS_DEFAULT "5"
#define CONF_MAX_PLAYLIST_LENGTH_DEFAULT "4096"
#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_OUTPUT_BUFFER_SIZE_DEFAULT "2048"
#define CONF_AO_DRIVER_DEFAULT AUDIO_AO_DRIVER_DEFAULT
#define CONF_AO_DRIVER_OPTIONS_DEFAULT ""
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS_DEFAULT "no"
#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] = {
"port",
......@@ -59,20 +75,26 @@ char * conf_strings[CONF_NUMBER_OF_PARAMS] = {
"max_connections",
"max_playlist_length",
"buffer_before_play",
"stop_on_error",
"max_command_list_size",
"max_output_buffer_size",
"ao_driver",
"ao_driver_options",
"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] = {
CONF_MUSIC_DIRECTORY,
CONF_PLAYLIST_DIRECTORY,
CONF_LOG_FILE,
CONF_ERROR_FILE
CONF_ERROR_FILE,
CONF_STATE_FILE,
CONF_DB_FILE
};
int conf_required[CONF_NUMBER_OF_REQUIRED] = {
......@@ -96,13 +118,15 @@ void initConf() {
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_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_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_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_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) {
......@@ -113,7 +137,7 @@ char ** readConf(char * file) {
int numberOfArgs;
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);
}
......@@ -122,13 +146,13 @@ char ** readConf(char * file) {
numberOfArgs = buffer2array(string,&array);
if(numberOfArgs==0) continue;
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);
}
i = 0;
while(i<CONF_NUMBER_OF_PARAMS && 0!=strcmp(conf_strings[i],array[0])) i++;
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);
}
if(conf_params[i]!=NULL) {
......@@ -144,14 +168,17 @@ char ** readConf(char * file) {
for(i=0;i<CONF_NUMBER_OF_REQUIRED;i++) {
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);
}
}
for(i=0;i<CONF_NUMBER_OF_PATHS;i++) {
if(conf_params[conf_absolutePaths[i]][0]!='/') {
fprintf(stderr,"\"%s\" is not an absolute path\n",conf_params[conf_absolutePaths[i]]);
if(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);
}
}
......@@ -168,12 +195,12 @@ void writeConf(char * file) {
FILE * fp;
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);
}
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);
......
......@@ -29,13 +29,17 @@
#define CONF_MAX_CONNECTIONS 7
#define CONF_MAX_PLAYLIST_LENGTH 8
#define CONF_BUFFER_BEFORE_PLAY 9
#define CONF_STOP_ON_ERROR 10
#define CONF_MAX_COMMAND_LIST_SIZE 11
#define CONF_MAX_OUTPUT_BUFFER_SIZE 12
#define CONF_AO_DRIVER 13
#define CONF_AO_DRIVER_OPTIONS 14
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 15
#define CONF_BIND_TO_ADDRESS 16
#define CONF_MAX_COMMAND_LIST_SIZE 10
#define CONF_MAX_OUTPUT_BUFFER_SIZE 11
#define CONF_AO_DRIVER 12
#define CONF_AO_DRIVER_OPTIONS 13
#define CONF_SAVE_ABSOLUTE_PATHS_IN_PLAYLISTS 14
#define CONF_BIND_TO_ADDRESS 15
#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 */
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 @@
#include "tables.h"
#include "utils.h"
#include "path.h"
#include "myfprintf.h"
#include "log.h"
#include "playlist.h"
#include <string.h>
......@@ -32,6 +32,7 @@
#include <dirent.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#define DIRECTORY_DIR "directory: "
#define DIRECTORY_MTIME "mtime: "
......@@ -66,7 +67,7 @@ int updateDirectory(Directory * directory);
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 = malloc(sizeof(Directory));
......@@ -76,8 +77,8 @@ Directory * newDirectory(Directory * parentDirectory, char * dirname) {
directory->parentDirectory = parentDirectory;
directory->subDirectories = newDirectoryList();
directory->songs = newSongList();
if(dirname!=NULL) directory->mtime = isDir(dirname);
else directory->mtime = 0;
if(mtime<0) directory->mtime = isDir(dirname);
else directory->mtime = mtime;
return directory;
}
......@@ -116,7 +117,7 @@ int updateInDirectory(Directory * directory, char * shortname, char * name) {
if((mtime = isMusic(name))) {
if(0==findInList(directory->songs,shortname,&song)) {
printf("adding %s\n",name);
LOG1("adding %s\n",name);
addToDirectory(directory,shortname,name);
}
else if(mtime>((Song *)song)->mtime) {
......@@ -243,7 +244,7 @@ int exploreDirectory(Directory * directory) {
if((dir = opendir(rmp2amp(dirname)))==NULL) return -1;
printf("explore: %s\n",dirname);
LOG1("explore: %s\n",dirname);
while((ent = readdir(dir))) {
if(ent->d_name[0]=='.') continue; /* hide hidden stuff */
if(directory->name) {
......@@ -261,7 +262,7 @@ int exploreDirectory(Directory * directory) {
}
int addSubDirectoryToDirectory(Directory * directory, char * shortname, char * name) {
Directory * subDirectory = newDirectory(directory,name);
Directory * subDirectory = newDirectory(directory,name,-1);
insertInList(directory->subDirectories,shortname,subDirectory);
exploreDirectory(subDirectory);
......@@ -294,6 +295,10 @@ Directory * findSubDirectory(Directory * directory,char * name) {
char * key;
key = strtok(dup,"/");
if(!key) {
free(dup);
return NULL;
}
if(findInList(directory->subDirectories,key,&subDirectory)) {
free(dup);
......@@ -338,7 +343,7 @@ int printDirectoryList(FILE * fp, DirectoryList * directoryList) {
return 0;
}
int printDirectoryInfo(FILE * fp,char * name) {
int printDirectoryInfo(FILE * fp, char * name) {
Directory * directory;
if((directory = getDirectory(name))==NULL) {
......@@ -356,19 +361,19 @@ void writeDirectoryInfo(FILE * fp, Directory * directory) {
ListNode * node = (directory->subDirectories)->firstNode;
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) {
subDirectory = (Directory *)node->data;
fprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key);
fprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime);
myfprintf(fp,"%s%s\n",DIRECTORY_DIR,node->key);
myfprintf(fp,"%s%li\n",DIRECTORY_MTIME,(long)subDirectory->mtime);
writeDirectoryInfo(fp,subDirectory);
node = node->nextNode;
}
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) {
......@@ -383,25 +388,25 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
if(0==strncmp(DIRECTORY_DIR,buffer,strlen(DIRECTORY_DIR))) {
key = strdup(&(buffer[strlen(DIRECTORY_DIR)]));
if(myFgets(buffer,bufferSize,fp)<0) {
fprintf(stderr,"Error reading db\n");
ERROR0("Error reading db\n");
exit(-1);
}
if(strncmp(DIRECTORY_MTIME,buffer,strlen(DIRECTORY_MTIME))) {
fprintf(stderr,"Error reading db\n");
printf("%s\n",buffer);
ERROR0("Error reading db\n");
ERROR1("%s\n",buffer);
exit(-1);
}
mtime = atoi(&(buffer[strlen(DIRECTORY_BEGIN)]));
if(myFgets(buffer,bufferSize,fp)<0) {
fprintf(stderr,"Error reading db\n");
ERROR0("Error reading db\n");
exit(-1);
}
if(strncmp(DIRECTORY_BEGIN,buffer,strlen(DIRECTORY_BEGIN))) {
fprintf(stderr,"Error reading db\n");
ERROR0("Error reading db\n");
exit(-1);
}
name = strdup(&(buffer[strlen(DIRECTORY_BEGIN)]));
subDirectory = newDirectory(directory,name);
subDirectory = newDirectory(directory,name,mtime);
insertInList(directory->subDirectories,key,(void *)subDirectory);
free(key);
free(name);
......@@ -411,7 +416,7 @@ void readDirectoryInfo(FILE * fp,Directory * directory) {
readSongInfoIntoList(fp,directory->songs);
}
else {
fprintf(stderr,"Unknown line in db: %s\n",buffer);
ERROR1("Unknown line in db: %s\n",buffer);
exit(-1);
}
}
......@@ -436,10 +441,10 @@ int writeDirectoryDB() {
sortDirectory(mp3rootDirectory);
if(!(fp=fopen(directorydb,"w"))) return -1;
while(!(fp=fopen(directorydb,"w")) && errno==EINTR);
if(!fp) return -1;
writeDirectoryInfo(fp,mp3rootDirectory);
fclose(fp);
while(fclose(fp) && errno==EINTR);
return 0;
}
......@@ -447,10 +452,11 @@ int writeDirectoryDB() {
int readDirectoryDB() {
FILE * fp;
mp3rootDirectory = newDirectory(NULL,NULL);
if(!(fp=fopen(directorydb,"r"))) return -1;
mp3rootDirectory = newDirectory(NULL,NULL,0);
while(!(fp=fopen(directorydb,"r")) && errno==EINTR);
if(!fp) return -1;
readDirectoryInfo(fp,mp3rootDirectory);
fclose(fp);
while(fclose(fp) && errno==EINTR);
sortDirectory(mp3rootDirectory);
......@@ -512,7 +518,7 @@ int printAllIn(FILE * fp, char * name) {
}
void initMp3Directory() {
mp3rootDirectory = newDirectory(NULL,NULL);
mp3rootDirectory = newDirectory(NULL,NULL,0);
exploreDirectory(mp3rootDirectory);
sortDirectory(mp3rootDirectory);
}
......
......@@ -36,8 +36,6 @@ int writeDirectoryDB();
int readDirectoryDB();
size_t getDirectoryLine(char ** buffer, int * size, FILE * fp);
int updateMp3Directory(FILE * fp);
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 @@
#ifndef FLAC_DECODE_H
#define FLAC_DECODE_H
#include "playerData.h"
#include <stdio.h>
int flac_decode(char * file, FILE * in, FILE * out);
int flac_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#endif
......@@ -21,17 +21,20 @@
#include "command.h"
#include "conf.h"
#include "list.h"
#include "myfprintf.h"
#include "log.h"
#include "listen.h"
#include "sig_handlers.h"
#include "playlist.h"
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/select.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
......@@ -59,8 +62,9 @@ typedef struct _Interface {
unsigned long long commandListSize; /* mem commandList consumes */
List * bufferList; /* for output if client is slow */
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 */
int num; /* interface number */
} Interface;
Interface * interfaces = NULL;
......@@ -72,11 +76,12 @@ void openInterface(Interface * interface, int fd) {
assert(interface->open==0);
blockSignals();
interface->bufferLength = 0;
interface->fd = fd;
fcntl(interface->fd,F_SETOWN,(int)getpid());
/* fcntl(interface->fd,F_SETOWN,(int)getpid()); */
flags = fcntl(fd,F_GETFL);
flags|=O_NONBLOCK | O_ASYNC;
flags|=O_NONBLOCK;
fcntl(interface->fd,F_SETFL,flags);
interface->fp = fdopen(fd,"rw");
interface->open = 1;
......@@ -85,6 +90,7 @@ void openInterface(Interface * interface, int fd) {
interface->bufferList = NULL;
interface->expired = 0;
interface->outputBufferSize = 0;
unblockSignals();
myfprintf(interface->fp,"%s %s %s\n",COMMAND_RESPOND_OK,GREETING,VERSION);
}
......@@ -94,46 +100,83 @@ void closeInterface(Interface * interface) {
interface->open = 0;
if(fclose(interface->fp)) {
fprintf(stderr,"Error closing file pointer\n");
}
while(fclose(interface->fp) && errno==EINTR);
if(interface->commandList) freeList(interface->commandList);
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;
for(i=0;i<interface_max_connections && interfaces[i].open;i++);
if(i==interface_max_connections) {
FILE * fp = fdopen(fd,"rw");
myfprintf(fp,"%s Max Connections Reached!\n",COMMAND_RESPOND_ERROR);
fclose(fp);
close(fd);
ERROR0("Max Connections Reached!\n");
while(close(fd) && errno==EINTR);
}
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);
}
}
int interfaceReadInput(Interface * interface) {
blockSignals();
if(read(interface->fd,interface->buffer+interface->bufferLength,1)>0) {
int ret = 1;
int bytesRead = 1;
while(bytesRead>0) {
interface->buffer[interface->bufferLength+1] = '\0';
if(interface->buffer[interface->bufferLength]!='\r') {
interface->bufferLength++;
}
if(interface->bufferLength>=INTERFACE_MAX_BUFFER_LENGTH) {
fprintf(stderr,"Buffer Overflow\n");
closeInterface(interface);
break;
}
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;
int argArrayLength;
interface->buffer[interface->bufferLength-1] = '\0';
interface->bufferLength = 0;
argArrayLength = buffer2array(interface->buffer,&argArray);
if(interface->commandList) {
......@@ -145,13 +188,15 @@ int interfaceReadInput(Interface * interface) {
char ** argArray;
int argArrayLength;
argArrayLength = buffer2array((char *)node->data,&argArray);
DEBUG2("interface %i: process command \"%s\"\n",interface->num,node->data);
ret = processCommand(interface->fp,argArrayLength,argArray);
DEBUG2("interface %i: command returned %i\n",interface->num,ret);
freeArgArray(argArray,argArrayLength);
node = node->nextNode;
if(ret!=0 ||
interface->expired) {
break;
node = NULL;
}
node = node->nextNode;
}
if(ret==0) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
......@@ -168,7 +213,7 @@ int interfaceReadInput(Interface * interface) {
interface->commandListSize+=sizeof(ListNode);
interface->commandListSize+=strlen(interface->buffer)+1;
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);
}
......@@ -189,7 +234,11 @@ int interfaceReadInput(Interface * interface) {
myfprintf(interface->fp,"%s not in command list mode\n",COMMAND_RESPOND_ERROR);
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) {
myfprintf(interface->fp,"%s\n",COMMAND_RESPOND_OK);
}
......@@ -200,11 +249,13 @@ int interfaceReadInput(Interface * interface) {
}
}
freeArgArray(argArray,argArrayLength);
interface->bufferLength = 0;
}
return ret;
}
else closeInterface(interface);
else {
unblockSignals();
closeInterface(interface);
}
return 1;
}
......@@ -270,7 +321,8 @@ int doIOForInterfaces() {
while((selret = select(FD_SETSIZE,&rfds,&wfds,NULL,&tv))) {
if(FD_ISSET(listenSocket,&rfds)) getConnections(listenSocket);
if(selret<0) {
if(selret<0 && errno==EINTR) break;
else if(selret<0) {
closeNextErroredInterface();
continue;
}
......@@ -301,25 +353,25 @@ void initInterfaces() {
interface_timeout = strtol((getConf())[CONF_CONNECTION_TIMEOUT],&test,10);
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);
}
interface_max_connections = strtol((getConf())[CONF_MAX_CONNECTIONS],&test,10);
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);
}
interface_max_command_list_size = strtoll((getConf())[CONF_MAX_COMMAND_LIST_SIZE],&test,10);
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);
}
interface_max_output_buffer_size = strtoll((getConf())[CONF_MAX_OUTPUT_BUFFER_SIZE],&test,10);
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);
}
......@@ -330,6 +382,7 @@ void initInterfaces() {
for(i=0;i<interface_max_connections;i++) {
interfaces[i].open = 0;
interfaces[i].num = i;
}
}
......@@ -356,6 +409,7 @@ void closeOldInterfaces() {
for(i=0;i<interface_max_connections;i++) {
if(interfaces[i].open && (interfaces[i].expired || (time(NULL)-interfaces[i].lastTime>interface_timeout))) {
DEBUG1("interface %i: timeout\n",i);
closeInterface(&(interfaces[i]));
}
}
......@@ -374,7 +428,7 @@ void closeInterfaceWithFD(int fd) {
void flushInterfaceBuffer(Interface * interface) {
ListNode * node = NULL;
char * str;
int ret;
int ret = 0;
while((node = interface->bufferList->firstNode)) {
str = (char *)node->data;
......@@ -394,11 +448,14 @@ void flushInterfaceBuffer(Interface * interface) {
}
if(!interface->bufferList->firstNode) {
DEBUG1("interface %i: buffer empty\n",interface->num);
freeList(interface->bufferList);
interface->bufferList = NULL;
}
else if(errno!=EAGAIN && errno!=EINTR) {
else if(ret<0 && errno!=EAGAIN && errno!=EINTR) {
/* cause interface to close */
DEBUG1("interface %i: problems flushing buffer\n",
interface->num);
freeList(interface->bufferList);
interface->bufferList = NULL;
interface->expired = 1;
......@@ -415,29 +472,33 @@ void flushAllInterfaceBuffers() {
}
}
void interfacePrintWithFD(int fd,char * buffer) {
int interfacePrintWithFD(int fd,char * buffer) {
int i;
int ret;
if(!strlen(buffer)) return;
if(!strlen(buffer)) return -1;
for(i=0;i<interface_max_connections;i++) {
if(interfaces[i].fd==fd) break;
}
/* 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) {
interfaces[i].outputBufferSize+=sizeof(ListNode);
interfaces[i].outputBufferSize+=strlen(buffer)+1;
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 */
freeList(interfaces[i].bufferList);
interfaces[i].bufferList = NULL;
interfaces[i].expired = 1;
return;
return 0;
}
else {
insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer));
......@@ -451,19 +512,23 @@ void interfacePrintWithFD(int fd,char * buffer) {
insertInListWithoutKey(interfaces[i].bufferList,(void *)strdup(buffer));
}
else {
DEBUG1("interface %i: problems writing\n",i);
interfaces[i].expired = 1;
return;
return 0;
}
}
else if(ret<strlen(buffer)) {
interfaces[i].bufferList = makeList(free);
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) {
DEBUG1("interface %i: buffer created\n",i);
interfaces[i].outputBufferSize = sizeof(List);
interfaces[i].outputBufferSize+=sizeof(ListNode);
interfaces[i].outputBufferSize+=strlen((char *)interfaces[i].bufferList->firstNode->data)+1;
}
}
return 0;
}
......@@ -21,15 +21,17 @@
#include <stdio.h>
#include <time.h>
#include <sys/types.h>
#include <sys/socket.h>
void initInterfaces();
void openAInterface(int fd);
void openAInterface(int fd, struct sockaddr * addr);
void closeAllInterfaces();
void freeAllInterfaces();
void closeOldInterfaces();
void closeInterfaceWithFD(int fd);
void flushAllInterfaceBuffers();
void interfacePrintWithFD(int fd, char * buffer);
int interfacePrintWithFD(int fd, char * buffer);
int doIOForInterfaces();
......
......@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library
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 @@
libid3tag - ID3 tag manipulation library
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 @@
## along with this program; if not, write to the Free Software
## 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
......
......@@ -66,12 +66,19 @@ EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
AWK = @AWK@
CC = @CC@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
......@@ -79,6 +86,7 @@ LN_S = @LN_S@
OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
am__include = @am__include@
......@@ -123,7 +131,7 @@ libid3tag_la_LDFLAGS = -version-info $(version_info)
BUILT_SOURCES = frametype.c compat.c genre.dat
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = libid3tag.list
LTLIBRARIES = $(noinst_LTLIBRARIES)
......@@ -141,7 +149,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
depcomp = $(SHELL) $(top_srcdir)/../../depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/compat.Plo ./$(DEPDIR)/crc.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/debug.Plo ./$(DEPDIR)/field.Plo \
......@@ -168,10 +176,11 @@ 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 = README $(noinst_HEADERS) ../config.guess ../config.sub \
../depcomp ../install-sh ../ltmain.sh ../missing \
../mkinstalldirs COPYING INSTALL Makefile.am Makefile.in TODO \
aclocal.m4 config.h.in configure configure.ac libid3tag.list.in
DIST_COMMON = README $(noinst_HEADERS) ../../config.guess \
../../config.sub ../../depcomp ../../install-sh ../../ltmain.sh \
../../missing ../../mkinstalldirs COPYING INSTALL Makefile.am \
Makefile.in TODO aclocal.m4 config.h.in configure configure.ac \
libid3tag.list.in
DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(libid3tag_la_SOURCES) $(EXTRA_libid3tag_la_SOURCES)
......@@ -394,7 +403,7 @@ distcleancheck_listfiles = find . -type f -print
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkinstalldirs) $(distdir)/. $(distdir)/..
$(mkinstalldirs) $(distdir)/. $(distdir)/../..
@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,/[^/]*$$,,'`; \
......
......@@ -2,7 +2,7 @@
libid3tag - ID3 tag manipulation library
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 @@
libid3tag - ID3 tag manipulation library
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 */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
......@@ -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
* 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
......
......@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
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
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
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.
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
/* 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 */
#if !((' ' == 32) && ('!' == 33) && ('"' == 34) && ('#' == 35) \
......@@ -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
* 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
......
......@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -17,7 +17,7 @@
* along with this program; if not, write to the Free Software
* 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 @@
* along with this program; if not, write to the Free Software
* 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 @@
# along with this program; if not, write to the Free Software
# 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\
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -19,7 +19,7 @@
* If you would like to negotiate alternate licensing terms, you may do
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library
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 @@
libmad - MPEG audio decoder library
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 @@
* along with this program; if not, write to the Free Software
* 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 @@
## along with this program; if not, write to the Free Software
## 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
......
......@@ -66,6 +66,7 @@ EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
AMTAR = @AMTAR@
AR = @AR@
AS = @AS@
ASO = @ASO@
ASO_OBJS = @ASO_OBJS@
......@@ -73,10 +74,16 @@ AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
DLLTOOL = @DLLTOOL@
ECHO = @ECHO@
EGREP = @EGREP@
F77 = @F77@
FPM = @FPM@
GCJ = @GCJ@
GCJFLAGS = @GCJFLAGS@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
LIBTOOL = @LIBTOOL@
LIBTOOL_DEPS = @LIBTOOL_DEPS@
......@@ -84,6 +91,7 @@ LN_S = @LN_S@
OBJDUMP = @OBJDUMP@
PACKAGE = @PACKAGE@
RANLIB = @RANLIB@
RC = @RC@
STRIP = @STRIP@
VERSION = @VERSION@
am__include = @am__include@
......@@ -142,7 +150,7 @@ version_info = $(version_current):$(version_revision):$(version_age)
libmad_la_LDFLAGS = -version-info $(version_info)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
mkinstalldirs = $(SHELL) $(top_srcdir)/../mkinstalldirs
mkinstalldirs = $(SHELL) $(top_srcdir)/../../mkinstalldirs
CONFIG_HEADER = config.h
CONFIG_CLEAN_FILES = libmad.list
LTLIBRARIES = $(noinst_LTLIBRARIES)
......@@ -164,7 +172,7 @@ DEFAULT_INCLUDES = -I. -I$(srcdir) -I.
CPPFLAGS = @CPPFLAGS@
LDFLAGS = @LDFLAGS@
LIBS = @LIBS@
depcomp = $(SHELL) $(top_srcdir)/../depcomp
depcomp = $(SHELL) $(top_srcdir)/../../depcomp
am__depfiles_maybe = depfiles
@AMDEP_TRUE@DEP_FILES = ./$(DEPDIR)/bit.Plo ./$(DEPDIR)/decoder.Plo \
@AMDEP_TRUE@ ./$(DEPDIR)/fixed.Plo ./$(DEPDIR)/frame.Plo \
......@@ -192,10 +200,11 @@ 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 = README $(noinst_HEADERS) ../config.guess ../config.sub \
../depcomp ../install-sh ../ltmain.sh ../missing \
../mkinstalldirs COPYING INSTALL Makefile.am Makefile.in TODO \
aclocal.m4 config.h.in configure configure.ac libmad.list.in
DIST_COMMON = README $(noinst_HEADERS) ../../config.guess \
../../config.sub ../../depcomp ../../install-sh ../../ltmain.sh \
../../missing ../../mkinstalldirs COPYING INSTALL Makefile.am \
Makefile.in TODO aclocal.m4 config.h.in configure configure.ac \
libmad.list.in
DIST_SUBDIRS = $(SUBDIRS)
SOURCES = $(libmad_la_SOURCES) $(EXTRA_libmad_la_SOURCES) $(minimad_SOURCES)
......@@ -425,7 +434,7 @@ distcleancheck_listfiles = find . -type f -print
distdir: $(DISTFILES)
$(am__remove_distdir)
mkdir $(distdir)
$(mkinstalldirs) $(distdir)/. $(distdir)/..
$(mkinstalldirs) $(distdir)/. $(distdir)/../..
@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,/[^/]*$$,,'`; \
......
......@@ -2,7 +2,7 @@
libmad - MPEG audio decoder library
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 @@
libmad - MPEG audio decoder library
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 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
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
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
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.
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -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>
* - Corrected PIC unsafe loading of address of 'imdct36_long_karray'
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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 */,
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -33,7 +33,7 @@ extern "C" {
# 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
# define LIBMAD_VERSION_H
......@@ -62,7 +62,7 @@ extern char const mad_build[];
# 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
# define LIBMAD_FIXED_H
......@@ -528,7 +528,7 @@ mad_fixed_t mad_f_div(mad_fixed_t, mad_fixed_t);
# 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
# define LIBMAD_BIT_H
......@@ -557,7 +557,7 @@ unsigned short mad_bit_crc(struct mad_bitptr, unsigned int, unsigned short);
# 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
# define LIBMAD_TIMER_H
......@@ -639,7 +639,7 @@ void mad_timer_string(mad_timer_t, char *, char const *,
# 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
# define LIBMAD_STREAM_H
......@@ -727,7 +727,7 @@ char const *mad_stream_errorstr(struct mad_stream const *);
# 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
# define LIBMAD_FRAME_H
......@@ -824,7 +824,7 @@ void mad_frame_mute(struct mad_frame *);
# 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
# define LIBMAD_SYNTH_H
......@@ -873,7 +873,7 @@ void mad_synth_frame(struct mad_synth *, struct mad_frame const *);
# 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
# define LIBMAD_DECODER_H
......
......@@ -16,7 +16,7 @@
# along with this program; if not, write to the Free Software
# 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 @@
* along with this program; if not, write to the Free Software
* 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>
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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 @@
* along with this program; if not, write to the Free Software
* 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 @@
* along with this program; if not, write to the Free Software
* 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 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -16,7 +16,7 @@
* along with this program; if not, write to the Free Software
* 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
......
......@@ -61,7 +61,7 @@ int insertInList(List * list,char * key,void * data) {
assert(list!=NULL);
assert(key!=NULL);
assert(data!=NULL);
/*assert(data!=NULL);*/
node = malloc(sizeof(ListNode));
assert(node!=NULL);
......
......@@ -46,13 +46,13 @@ typedef struct _List {
ListNode * lastNode;
/* function used to free data stored in nodes of the list */
ListFreeDataFunc * freeDataFunc;
/* number of ndoes */
/* number of nodes */
long numberOfNodes;
/* array for searching when list is sorted */
ListNode ** nodesArray;
} 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
* DEFAULT_FREE_DATAFUNC to use free()
* returns pointer to new list if successful, NULL otherwise
......@@ -82,12 +82,12 @@ void deleteNodeFromList(List * list,ListNode * node);
* _list_ -> list to search for _key_ in
* _key_ -> which node is being searched for
* _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
*/
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
*/
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 @@
#include <string.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) {
DIR * dir;
char cwd[2];
char c;
struct stat st;
struct dirent * ent;
char s[MAXPATHLEN];
char s[MAXPATHLEN+1];
cwd[0] = '.';
cwd[1] = '\0';
......@@ -68,31 +78,38 @@ int ls(FILE * fp, char * dirname) {
return 0;
}
int lsPlaylists(FILE * fp) {
int lsPlaylists(FILE * fp, char * path) {
DIR * dir;
struct stat st;
struct dirent * ent;
char * cLast;
char * cNext;
char * dup;
char s[MAXPATHLEN];
char s[MAXPATHLEN+1];
List * list = NULL;
ListNode * node = NULL;
char * actualPath = rpp2app(path);
if((dir = opendir(playlistDir))==NULL) {
myfprintf(fp,"%s problems opening playlist directory\n",COMMAND_RESPOND_ERROR);
return -1;
}
if((dir = opendir(actualPath))==NULL) return 0;
while((ent = readdir(dir))) {
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(S_ISREG(st.st_mode)) {
dup = strdup(ent->d_name);
cNext = cLast = strtok(dup,".");
while((cNext = strtok(NULL,"."))) cLast = cNext;
if(cLast && 0==strcmp(cLast,PLAYLIST_FILE_SUFFIX)) {
strncpy(dup,ent->d_name,strlen(ent->d_name)-strlen(PLAYLIST_FILE_SUFFIX)-1);
myfprintf(fp,"playlist: %s\n",dup);
if(cLast && 0==strcmp(cLast,
PLAYLIST_FILE_SUFFIX))
{
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);
}
......@@ -101,6 +118,24 @@ int lsPlaylists(FILE * fp) {
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;
}
......@@ -120,6 +155,35 @@ time_t isMusic(char * file) {
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) {
struct stat st;
char * actualFile = file;
......
......@@ -24,7 +24,7 @@
int ls(FILE * fp, char * dir);
int lsPlaylists(FILE * fp);
int lsPlaylists(FILE * fp, char * path);
time_t isMp3(char * file);
......@@ -36,4 +36,8 @@ time_t isMusic(char * file);
time_t isDir(char * name);
time_t isPlaylist(char * file);
char * dupAndStripPlaylistSuffix(char * file);
#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 @@
#ifdef HAVE_MAD
#include "mp3_decode.h"
#include "player.h"
#include "command.h"
#include "utils.h"
#include "audio.h"
#ifdef USE_MPD_MAD
#include "libmad/mad.h"
#else
#include <mad.h>
#endif
#include "buffer.h"
#include "playerData.h"
#include "log.h"
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/wait.h>
#include <signal.h>
#include <ao/ao.h>
#define INPUT_BUFFER_SIZE 80
#define TIME_TELL_INTERVAL 0.2
#include <sys/stat.h>
#include <unistd.h>
#define CHECK_INPUT_FREQ 300 /* about once very 0.1 seconds */
#define FRAMES_CUSHION 2000
#define READ_BUFFER_SIZE 40960
......@@ -54,10 +41,6 @@
#define DECODE_CONT -1
#define DECODE_OK 0
int mp3_decode_pid = 0;
int mp3_decode_done = 0;
ao_device * mp3_device = 0;
/* this is stolen from mpg321! */
struct audio_dither {
mad_fixed_t error[3];
......@@ -125,31 +108,47 @@ typedef struct _mp3DecodeData {
char outputBuffer[CHUNK_SIZE];
char * outputPtr;
char * outputBufferEnd;
unsigned long frameCount;
int status;
float totalTime;
float elapsedTime;
int start;
int muteFrame;
long * frameOffset;
mad_timer_t * times;
long highestFrame;
long currentOffset;
long maxFrames;
long currentFrame;
int flush;
} mp3DecodeData;
void initMp3DecodeData(mp3DecodeData * data) {
data->outputPtr = data->outputBuffer;
data->outputBufferEnd = data->outputBuffer+CHUNK_SIZE;
data->frameCount = 0;
data->status = 0;
data->start = 0;
data->muteFrame = 0;
data->currentOffset = 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_frame_init(&data->frame);
mad_synth_init(&data->synth);
mad_timer_reset(&data->timer);
}
int fillMp3InputBuffer(mp3DecodeData * data) {
int fillMp3InputBuffer(mp3DecodeData * data, long offset) {
size_t readSize;
size_t remaining;
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;
memmove(data->readBuffer,(data->stream).next_frame,remaining);
readStart = (data->readBuffer)+remaining;
......@@ -164,53 +163,192 @@ int fillMp3InputBuffer(mp3DecodeData * data) {
readSize = fread(readStart,1,readSize,data->fp);
if(readSize<=0) return -1;
data->currentOffset+=readSize;
mad_stream_buffer(&data->stream,data->readBuffer,readSize+remaining);
(data->stream).error = 0;
return 0;
}
int decodeNextFrame(mp3DecodeData * data) {
if((data->stream).buffer==NULL || (data->stream).error==MAD_ERROR_BUFLEN)
if(fillMp3InputBuffer(data) < 0) return DECODE_BREAK;
int decodeNextFrameHeader(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_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_RECOVERABLE((data->stream).error)) return DECODE_CONT;
else {
if((data->stream).error==MAD_ERROR_BUFLEN) return DECODE_CONT;
else
{
fprintf(stderr,"unrecoverable frame level error (%s).\n",mad_stream_errorstr(&data->stream));
data->status = 1;
ERROR1("unrecoverable frame level error "
"(%s).\n",
mad_stream_errorstr(&data->stream));
data->flush = 0;
return DECODE_BREAK;
}
}
}
data->frameCount++;
return DECODE_OK;
}
int openMp3(char * file, mp3DecodeData * data) {
int ret;
/* xing stuff stolen from alsaplayer */
# 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 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) {
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;
}
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) {
while(cb->begin==cb->end && cb->wrap) usleep(100);
int mp3ChildSendData(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
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);
cb->chunkSize[cb->end] = data->outputPtr-data->outputBuffer;
cb->times[cb->end] = data->elapsedTime;
cb->end++;
......@@ -218,19 +356,47 @@ void mp3ChildSendData(mp3DecodeData * data, Buffer * cb) {
cb->end = 0;
cb->wrap = 1;
}
return 0;
}
int mp3Read(mp3DecodeData * data, Buffer * cb) {
int mp3Read(mp3DecodeData * data, Buffer * cb, DecoderControl * dc) {
static int i;
static int ret;
static struct audio_dither dither;
if(data->currentFrame>=data->highestFrame &&
data->highestFrame<data->maxFrames)
{
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);
data->elapsedTime = ((float)mad_timer_count(data->timer,MAD_UNITS_MILLISECONDS))/1000;
for(i=0;i<(data->synth).pcm.length;i++) {
signed int sample;
......@@ -245,196 +411,77 @@ int mp3Read(mp3DecodeData * data, Buffer * cb) {
}
if(data->outputPtr==data->outputBufferEnd) {
mp3ChildSendData(data,cb);
if(mp3ChildSendData(data,cb,dc)<0) {
data->flush = 0;
return DECODE_BREAK;
}
data->outputPtr = data->outputBuffer;
if(dc->seek) break;
}
}
while((ret=decodeNextFrame(data))==DECODE_CONT);
return ret;
}
ao_device * initAoDeviceFromMp3DecodeData(mp3DecodeData * data) {
ao_sample_format format;
ao_device * device;
format.bits = 16;
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(dc->seek) {
long i = 0;
cb->wrap = 0;
cb->end = 0;
data->muteFrame = 1;
while(i<data->highestFrame && dc->seekWhere >
((float)mad_timer_count(data->times[i],
MAD_UNITS_MILLISECONDS))/1000)
{
i++;
}
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;
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 = 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);
if(data->muteFrame) {
while((ret=decodeNextFrameHeader(data))==DECODE_CONT);
}
else while((ret=decodeNextFrame(data))==DECODE_CONT);
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);
/* END OF CHILD */
}
else if(mp3_decode_pid<0) {
fprintf(stderr,"%s mp3_decode Problems fork'ing\n",COMMAND_RESPOND_ERROR);
return PLAYER_EXIT_ERROR_SYSTEM;
if(openMp3(dc->file,&data) < 0) {
ERROR0("Input does not appear to be a mp3 bit stream.\n");
return -1;
}
{
/* 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();
initAudioFormatFromMp3DecodeData(&data,af);
cb->totalTime = data.totalTime;
dc->start = 0;
dc->state = DECODE_STATE_DECODE;
mp3_device = initAoDeviceFromMp3DecodeData(&data);
if(mp3_device == NULL) {
audioError();
pid = mp3_decode_pid;
if(pid>0) kill(pid,SIGTERM);
return PLAYER_EXIT_ERROR_AUDIO;
while(mp3Read(&data,cb,dc)!=DECODE_BREAK);
/* send last little bit if not dc->stop */
if(data.outputPtr!=data.outputBuffer && data.flush) {
mp3ChildSendData(&data,cb,dc);
}
mp3DecodeDataFinalize(&data);
fprintf(out,"%s\n",PLAYER_START);
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);
if(dc->seek) dc->seek = 0;
ao_close(mp3_device);
finishAudio();
/* END OF PARENT */
if(dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
}
else dc->state = DECODE_STATE_STOP;
return 0;
}
......
......@@ -19,8 +19,8 @@
#ifndef 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
/* 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 @@
* 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];
char playlistDir[MAXPATHLEN+1];
void myfprintfStdLogMode(FILE * out, FILE * err);
char * rmp2amp(char * relativePath) {
static char absolutePath[MAXPATHLEN+1];
void myfprintf(FILE * fp, char * format, ... );
strcpy(absolutePath,musicDir);
strcat(absolutePath,relativePath);
return absolutePath;
}
#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 "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 @@
#ifndef OGG_DECODE_H
#define OGG_DECODE_H
#include "playerData.h"
#include <stdio.h>
int ogg_decode(char * file, FILE * in, FILE * out);
int ogg_decode(Buffer * cb, AudioFormat * af, DecoderControl * dc);
#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];
*/
char * rmp2amp(char * file);
/* static char * returned */
char * rpp2app(char * file);
/* static char * returned */
char * parentPath(char * path);
#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 @@
#define PLAYER_H
#include <stdio.h>
#include <sys/param.h>
#define PLAYER_STATE_STOP 0
#define PLAYER_STATE_PAUSE 1
#define PLAYER_STATE_PLAY 2
#define PLAYER_ERROR "@ERROR"
#define PLAYER_START "@START"
#define PLAYER_TIME "@TIME"
#define PLAYER_PAUSE_GOT "@PAUSE_GOT"
#define PLAYER_ERROR_NOERROR 0
#define PLAYER_ERROR_FILE 1
#define PLAYER_ERROR_AUDIO 2
#define PLAYER_ERROR_SYSTEM 3
#define PLAYER_ERROR_UNKTYPE 4
#define PLAYER_ERROR_FILENOTFOUND 5
#define PLAYER_PAUSE "pause"
#define PLAYER_EXIT_ERROR_FILE 1
#define PLAYER_EXIT_ERROR_AUDIO 2
#define PLAYER_EXIT_ERROR_SYSTEM 3
/* 0->1->2->3->5 regular playback
* ->4->0 don't play queued song
*/
#define PLAYER_QUEUE_BLANK 0
#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);
......@@ -44,6 +74,10 @@ int playerPause(FILE * fp);
int playerStop(FILE * fp);
void playerCloseAudio();
void playerKill();
void playerProcessMessages();
int getPlayerTotalTime();
......@@ -54,6 +88,22 @@ int getPlayerState();
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
......@@ -16,9 +16,9 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "buffer.h"
#include "command.h"
#include "playerData.h"
#include "conf.h"
#include "log.h"
#include <sys/types.h>
#include <sys/ipc.h>
......@@ -28,16 +28,18 @@
int buffered_before_play;
int buffer_shmid;
Buffer * buffer_b;
PlayerData * playerData_pd;
void initBuffer() {
void initPlayerData() {
float perc;
char * test;
int shmid;
perc = strtod((getConf())[CONF_BUFFER_BEFORE_PLAY],&test);
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);
}
buffered_before_play = (perc/100)*BUFFERED_CHUNKS;
......@@ -46,24 +48,42 @@ void initBuffer() {
}
else if(buffered_before_play<0) buffered_before_play = 0;
if((buffer_shmid = shmget(IPC_PRIVATE,sizeof(Buffer),IPC_CREAT|0666))<0) {
fprintf(stderr,"%s shmget'ing\n",COMMAND_RESPOND_ERROR);
if((shmid = shmget(IPC_PRIVATE,sizeof(PlayerData),IPC_CREAT|0600))<0) {
ERROR0("problems shmget'ing\n");
exit(-1);
}
if((buffer_b = shmat(buffer_shmid,NULL,0))<0) {
fprintf(stderr,"%s shmat'ing\n",COMMAND_RESPOND_ERROR);
if((playerData_pd = shmat(shmid,NULL,0))<0) {
ERROR0("problems shmat'ing\n");
exit(-1);
}
if (shmctl(buffer_shmid, IPC_RMID, 0)<0) {
fprintf(stderr,"%s shmctl'ing\n",COMMAND_RESPOND_ERROR);
if (shmctl(shmid, IPC_RMID, 0)<0) {
ERROR0("problems shmctl'ing\n");
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() {
return buffer_b;
PlayerData * getPlayerData() {
return playerData_pd;
}
void freeBuffer() {
shmdt(buffer_b);
void freePlayerData() {
shmdt(playerData_pd);
}
......@@ -16,28 +16,45 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef BUFFER_H
#define BUFFER_H
#ifndef PLAYER_DATA_H
#define PLAYER_DATA_H
#include "audio.h"
#include "player.h"
#include "decode.h"
/*
#define CHUNK_SIZE 256
#define BUFFERED_CHUNKS 8192 /* 2 MB of buffer */
#define BUFFERED_CHUNKS 8192
#define PLAY_SIZE 64
*/
#define CHUNK_SIZE 64
#define BUFFERED_CHUNKS 32768 /* 2 MB of buffer */
extern int buffered_before_play;
typedef struct _Buffer {
char chunks[BUFFERED_CHUNKS][CHUNK_SIZE];
unsigned char chunkSize[BUFFERED_CHUNKS];
float times[BUFFERED_CHUNKS];
int begin;
int end;
int next;
int wrap;
int finished;
float totalTime;
} 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
/* 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 @@
#define PLAYLIST_FILE_SUFFIX "m3u"
typedef struct _Playlist {
Song ** songs;
int length;
int current;
int repeat;
unsigned long version;
} Playlist;
void initPlaylist();
void finishPlaylist();
void initPlaylist();
void readPlaylistState();
void savePlaylistState();
int clearPlaylist(FILE * fp);
int addToPlaylist(FILE * fp, char * file);
......@@ -49,11 +49,11 @@ int playlistInfo(FILE * fp, int song);
int stopPlaylist(FILE * fp);
int playPlaylist(FILE * fp, int song);
int playPlaylist(FILE * fp, int song, int stopOnError);
int nextSongInPlaylist(FILE * fp);
void nextSongInPlaylistIfPlayerStopped();
void syncPlayerAndPlaylist();
int previousSongInPlaylist(FILE * fp);
......@@ -67,10 +67,28 @@ void deleteASongFromPlaylist(Song * song);
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 getPlaylistRepeatStatus();
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
/* 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 @@
#include "tables.h"
#include "utils.h"
#include "tag.h"
#include "myfprintf.h"
#include "log.h"
#define SONG_KEY "key: "
#define SONG_FILE "file: "
......@@ -116,16 +116,16 @@ int printSongInfoFromList(FILE * fp, SongList * list) {
void writeSongInfoFromList(FILE * fp, SongList * list) {
ListNode * tempNode = list->firstNode;
fprintf(fp,"%s\n",SONG_BEGIN);
myfprintf(fp,"%s\n",SONG_BEGIN);
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);
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;
}
fprintf(fp,"%s\n",SONG_END);
myfprintf(fp,"%s\n",SONG_END);
}
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))) {
if(!song || song->file) {
fprintf(stderr,"Problems reading song info\n");
ERROR0("Problems reading song info\n");
exit(-1);
}
song->file = strdup(&(buffer[strlen(SONG_FILE)]));
......@@ -173,7 +173,7 @@ void readSongInfoIntoList(FILE * fp, SongList * list) {
song->mtime = atoi(&(buffer[strlen(SONG_TITLE)]));
}
else {
fprintf(stderr,"unknown line in db: %s\n",buffer);
ERROR1("unknown line in db: %s\n",buffer);
exit(-1);
}
}
......
......@@ -28,8 +28,8 @@ Stats stats;
void initStats() {
stats.daemonStart = time(NULL);
stats.playTime = 0;
stats.songsPlayed = 0;
/*stats.playTime = 0;
stats.songsPlayed = 0;*/
}
int printStats(FILE * fp) {
......@@ -37,8 +37,8 @@ int printStats(FILE * fp) {
myfprintf(fp,"albums: %li\n",numberOfAlbums());
myfprintf(fp,"songs: %li\n",numberOfSongs());
myfprintf(fp,"uptime: %li\n",time(NULL)-stats.daemonStart);
myfprintf(fp,"playtime: %li\n",stats.playTime);
myfprintf(fp,"songs_played: %li\n",stats.songsPlayed);
/*myfprintf(fp,"playtime: %li\n",stats.playTime);
myfprintf(fp,"songs_played: %li\n",stats.songsPlayed);*/
myfprintf(fp,"db_update: %li\n",getDbModTime());
return 0;
}
......@@ -23,8 +23,8 @@
typedef struct _Stats {
unsigned long daemonStart;
unsigned long playTime;
unsigned long songsPlayed;
/*unsigned long playTime;
unsigned long songsPlayed;*/
} Stats;
extern Stats stats;
......
......@@ -134,7 +134,7 @@ int findAndPrintSongsInTable(FILE * fp, char * table, char * 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;
}
......@@ -254,7 +254,7 @@ int searchForSongsInTable(FILE * fp, char * table, char * 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;
}
......
......@@ -19,12 +19,14 @@
#include "tag.h"
#include "path.h"
#include "myfprintf.h"
#include "sig_handlers.h"
#include <sys/stat.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <errno.h>
#ifdef HAVE_OGG
#include <vorbis/vorbisfile.h>
#endif
......@@ -79,11 +81,19 @@ MpdTag * id3Dup(char * filename) {
struct id3_tag * tag;
char * str;
blockSignals();
file = id3_file_open(rmp2amp(filename),ID3_FILE_MODE_READONLY);
if(!file) return NULL;
if(!file) {
unblockSignals();
return NULL;
}
tag = id3_file_tag(file);
if(!tag) return NULL;
if(!tag) {
id3_file_close(file);
unblockSignals();
return NULL;
}
str = getID3Info(tag,ID3_FRAME_ARTIST);
if(str) {
......@@ -117,6 +127,7 @@ MpdTag * id3Dup(char * filename) {
if(!ret->title) ret->title = strdup("");
if(!ret->track) ret->track = strdup("");
}
unblockSignals();
#endif
return ret;
}
......@@ -131,8 +142,14 @@ MpdTag * oggCommentDup(char * file) {
char * s1;
char * s2;
if(!(fp = fopen(rmp2amp(file),"r"))) return NULL;
if(ov_open(fp,&vf,NULL,0)<0) return NULL;
while(!(fp = fopen(rmp2amp(file),"r")) && errno==EINTR);
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;
......@@ -169,6 +186,7 @@ MpdTag * oggCommentDup(char * file) {
if(!ret->track) ret->track = strdup("");
}
unblockSignals();
return ret;
}
#endif
......@@ -182,9 +200,11 @@ MpdTag * flacVorbisCommentDup(char * file) {
int offset;
int len, pos;
blockSignals();
it = FLAC__metadata_simple_iterator_new();
if(!FLAC__metadata_simple_iterator_init(it,rmp2amp(file),1,0)) {
FLAC__metadata_simple_iterator_delete(it);
unblockSignals();
return ret;
}
......@@ -249,6 +269,7 @@ MpdTag * flacVorbisCommentDup(char * file) {
if(block) FLAC__metadata_object_delete(block);
FLAC__metadata_simple_iterator_delete(it);
unblockSignals();
return ret;
}
#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 @@
#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 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