Commit 9f1f615e authored by Led's avatar Led

0.12.0rc1

parent a953cd9b
Developer -> Warren Dukes <shank@mercury.chem.pitt.edu>
Developer -> Warren Dukes <warren.dukes@gmail.com>
Developer -> tw-nym
audiofile support and command.c cleanup -> normalperson
setuid patch -> Nagilum
......@@ -6,5 +6,5 @@ setuid patch -> Nagilum
command.c and signal handling cleanup -> mackstann
replayGain -> AliasMrJones
libid3tag and libmad copyrighted by Robert Leslie, http://www.underbit.com/products/mad
mp4ff copyrighted by M. Bakker, Ahead Software AG, http://www.nero.com
compress.[ch] copyrighted by fluffy <fluffy@beesbuzz.biz>
ver 0.11.5 (2004/11/1a
ver 0.11.5 (2004/11/1)
1) New id3v1_ecnoding config option to configure the id3v1 tag encoding (patch from dottemag)
2) Strip '\r' from m3u playlists (thank you windows)
3) Use random() instead of rand() for playlist randomizing
......
......@@ -2,5 +2,8 @@ AUTOMAKE_OPTIONS = foreign 1.6
SUBDIRS = src doc
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING
doc_DATA = README UPGRADING
EXTRA_DIST = COPYING $(doc_DATA)
sparse-check:
$(MAKE) -C src $@
......@@ -65,6 +65,8 @@ host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
......@@ -75,8 +77,6 @@ AUDIOFILE_CONFIG = @AUDIOFILE_CONFIG@
AUDIOFILE_LIBS = @AUDIOFILE_LIBS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
......@@ -86,8 +86,6 @@ 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@
......@@ -95,10 +93,10 @@ LIBMIKMOD_CFLAGS = @LIBMIKMOD_CFLAGS@
LIBMIKMOD_CONFIG = @LIBMIKMOD_CONFIG@
LIBMIKMOD_LDADD = @LIBMIKMOD_LDADD@
LIBMIKMOD_LIBS = @LIBMIKMOD_LIBS@
LIBOGGFLAC_CFLAGS = @LIBOGGFLAC_CFLAGS@
LIBOGGFLAC_LIBS = @LIBOGGFLAC_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MP4FF_LIB = @MP4FF_LIB@
MP4FF_SUBDIR = @MP4FF_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
......@@ -108,6 +106,7 @@ OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
PKGCONFIG = @PKGCONFIG@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
RC = @RC@
SHOUTCONFIG = @SHOUTCONFIG@
......@@ -124,7 +123,7 @@ AUTOMAKE_OPTIONS = foreign 1.6
SUBDIRS = src doc
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = README UPGRADING
doc_DATA = README UPGRADING
EXTRA_DIST = COPYING $(doc_DATA)
subdir = .
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
......@@ -494,6 +493,9 @@ uninstall-info: uninstall-info-recursive
uninstall uninstall-am uninstall-docDATA uninstall-info-am \
uninstall-info-recursive uninstall-recursive
sparse-check:
$(MAKE) -C src $@
# 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:
0.12
0.13
----
*) add genre and date metadata
*) add support for coverart using freedesktop standard for icons/images
*) data structures
*) add 2-3 tree for sorted data structures
*) remove changes made to linked list for TagTracker
*) input plugins
*) add support for playing aac streams
*) mixer
*) add sun support
*) add OS X support
*) Add support for 24-bit audio
*) cleanup linked list code!
*) implement listener socket protocol as documented here:
http://www.musicpd.org/wiki/moin.cgi/MpdListenerProtocol
*) support for dynamically loading plugins
*) cleanup input plugins "API"
*) cleanup output plugins "API"
*) input plugins
*) Handle mp1 and mp2 files (including files with mp3 suffixes)
*) add error codes for status->error
*) Cleanup Config File Code
*) audio output
*) write a esd native audioOutput
*) write a nas native audioOutput
*) need better resampling code
*) allowing "pausing" of audio output devices
*) while pausing, play silence for the devices that don't support
"pausing"
*) write a sun native audioOutput
*) more accurate time reporting by determining how much of audio_device
buffer has been played
*) state
*) abstract out state code from playlist.c
*) put MPD Version in statefile
*) rewrite saved playlist code
*) abstract out saved playlists from playlist.c
......@@ -16,36 +57,41 @@
with saved playlist and
keep playing */
*) state
*) abstract out state code from playlist.c
*) save states of audioOutput devices
*) put MPD Version in statefile
*) add command for inserting songs in a specific position
*) put more debugging info when failing to read/write db and other similar
errors
*) make libao optional during configure, but check that some form of audioOutput
is enabled (either oss, shout, or ao)
1.0
---
*) Fix id3v1 encoding
*) bug fixes
*) Cleanup Config File Code
*) Optimize read() on clients
0.13
post-1.0
----
*) support for dynamically loading plugins
*) rewrite metadata/db handling
*) store all metadata entries in table
*) each contains a counter reference
*) new MpdDBTag, which instead of strings allocated for each metadata
entry, store a char * string to the metadata entry in the table
*) multiple artist support
*) multiple genre support {char *, int pairs for each metadata entry
indicating the type of metadata and its value)
*) MpdDBTag <-> MpdTag interface
*) rewrite audio pipe
*) use pthreads/clone
*) try to constrain the use of pthread mutex's and condition's
to specific output plugins
*) use pull model for audio_output
*) threads
0) managing thread
*) receives commands
*) manages state
*) handles time/metadata sending
1) decoding thread
2) effects thread
*) crossfading
*) *command* resampling/conversions
3) audio_output thread
*) thread for each audio_output device
*) dynamic metadata
*) implement by recording the ftell positions of entries
*) buffer changes and flush them once every 60 seconds
*) buffer changes while doing an update
*) be sure to check that the metadata "header" is what we expect
before writing at the position
*) add support for:
*) last time played
*) times played
*) times skipped
*) ranking
......@@ -9,7 +9,7 @@ any changes. However, if you downgrade back to 0.10.x, then you will need
to recreate your db.
The default port for MPD is now 6600, so update your mpd and client
configurations appropriatly.
configurations appropriately.
Upgrading to 0.10.0
-------------------
......@@ -21,7 +21,7 @@ recommended that you recreate the db. To do so, run mpd with the
character set will be determined from your current locale settings.
If your locale settings are not the same as those used for the filesystem,
then use the config file parameter "filesystem_charset" to specify the
correct character set (this maybe neccessary if you create the db with root).
correct character set (this maybe necessary if you create the db with root).
Upgrading to 0.9.3
------------------
......
This source diff could not be displayed because it is too large. You can view the blob instead.
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if alsa support is present */
/* Define to enable ALSA support */
#undef HAVE_ALSA
/* Define to play audio */
#undef HAVE_AUDIO
/* Define to play with ao */
#undef HAVE_AO
/* Define for audiofile support */
#undef HAVE_AUDIOFILE
......@@ -52,9 +52,15 @@
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
#undef HAVE_LANGINFO_CODESET
/* Define to 1 if you have the `asound' library (-lasound). */
#undef HAVE_LIBASOUND
/* Define to 1 if you have the `FLAC' library (-lFLAC). */
#undef HAVE_LIBFLAC
/* Define to 1 if you have the `vorbisidec' library (-lvorbisidec). */
#undef HAVE_LIBVORBISIDEC
/* Define if locale.h is present */
#undef HAVE_LOCALE
......@@ -73,12 +79,30 @@
/* Define to 1 if the system has the type `mp4AudioSpecificConfig'. */
#undef HAVE_MP4AUDIOSPECIFICCONFIG
/* Define for ogg vorbis support */
#undef HAVE_OGG
/* Define to use libmpcdec for MPC decoding */
#undef HAVE_MPCDEC
/* Define to enable Hauppauge Media MVP support */
#undef HAVE_MVP
/* Define for OggFLAC support */
#undef HAVE_OGGFLAC
/* Define for Ogg Vorbis support */
#undef HAVE_OGGVORBIS
/* Define to enable OSS */
#undef HAVE_OSS
/* Define for compiling OS X support */
#undef HAVE_OSX
/* Define to enable PulseAudio */
#undef HAVE_PULSE
/* Define to 1 if you have the `setenv' function. */
#undef HAVE_SETENV
/* Define to enable libshout support */
#undef HAVE_SHOUT
......@@ -97,7 +121,10 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define if sys/types.h present */
/* Define to enable SUN audio support */
#undef HAVE_SUN
/* Define if sys/inttypes.h present */
#undef HAVE_SYS_INTTYPES_H
/* Define to 1 if you have the <sys/stat.h> header file. */
......@@ -106,6 +133,9 @@
/* Define to 1 if you have the <sys/types.h> header file. */
#undef HAVE_SYS_TYPES_H
/* Define to use tremor (libvorbisidec) for ogg support */
#undef HAVE_TREMOR
/* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H
......@@ -142,12 +172,6 @@
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define to use mpd libid3tag */
#undef USE_MPD_ID3TAG
/* Define to use mpd libmad */
#undef USE_MPD_MAD
/* Version number of package */
#undef VERSION
......
This source diff could not be displayed because it is too large. You can view the blob instead.
Music Player Daemon - Commands
WARNING
This document has not been updated to reflect recent changes in
the MPD protocol. It does not contain all supported commands,
and some commands may now take additional arguments. However,
clients conforming to this specification should still be
compatible with the latest release of MPD. For more up to date
documentation, please see the protocol reference on the wiki at
<http://mpd.wikia.com/wiki/Protocol_Reference>.
This document is intended for client developers, not end users.
Format:
......@@ -103,7 +112,7 @@ move <int from> <int to>
move song at _from_ to _to_ in the playlist
increments playlist version by 1
move <int songid> <int to>
moveid <int songid> <int to>
move song with _songid_ to _to_ in the playlist
increments playlist version by 1
......@@ -113,7 +122,7 @@ next
pause <bool pause>
toggle pause/resume playing
_pause_ is required and should be 0 or 1
NOTE: use of pause command w/o the _pause_ argument is depricated
NOTE: use of pause command w/o the _pause_ argument is deprecated
password <string password>
this is used for authentication with the server.
......@@ -134,11 +143,11 @@ playlist
playlistinfo <int song>
displays list of songs in the playlist
_song_ is optional and species a single song to displa info for
_song_ is optional and specifies a single song to display info for
playlistid <int songid>
displays list of songs in the playlist
_songid_ is optional and species a single song to display info for
_songid_ is optional and specifies a single song to display info for
plchanges <playlist version>
displays changed songs currently in the playlist since
......@@ -146,6 +155,13 @@ plchanges <playlist version>
NOTE: to detect songs that were deleted at the end of the playlist,
use playlistlength returned by status command.
plchangesposid <playlist version>
displays changed songs currently in the playlist since
_playlist version_
This function only returns the position and the id of the changed song, not the complete metadata. This is more bandwidth efficient.
NOTE: to detect songs that were deleted at the end of the playlist,
use playlistlength returned by status command.
previous
plays previous song in playlist
......@@ -228,7 +244,7 @@ update <string path>
in status, while the requested update is happening
increments playlist version by 1
NOTE: To update a number of paths/songs at once, use command_list,
it will be much more faster/effecient. Also, if you use a
it will be much more faster/efficient. Also, if you use a
command_list for updating, only one update_db job id will be returned
per sequence of updates.
......
man_MANS = mpd.1
man_MANS = mpd.1 mpd.conf.5
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = COMMANDS
EXTRA_DIST = mpdconf.example $(man_MANS) $(doc_DATA)
doc_DATA = COMMANDS mpdconf.example
EXTRA_DIST = $(man_MANS) $(doc_DATA)
......@@ -65,6 +65,8 @@ host_triplet = @host@
EXEEXT = @EXEEXT@
OBJEXT = @OBJEXT@
PATH_SEPARATOR = @PATH_SEPARATOR@
ALSA_CFLAGS = @ALSA_CFLAGS@
ALSA_LIBS = @ALSA_LIBS@
AMTAR = @AMTAR@
AO_CFLAGS = @AO_CFLAGS@
AO_LIBS = @AO_LIBS@
......@@ -75,8 +77,6 @@ AUDIOFILE_CONFIG = @AUDIOFILE_CONFIG@
AUDIOFILE_LIBS = @AUDIOFILE_LIBS@
AWK = @AWK@
CC = @CC@
CCAS = @CCAS@
CCASFLAGS = @CCASFLAGS@
CXX = @CXX@
CXXCPP = @CXXCPP@
DEPDIR = @DEPDIR@
......@@ -86,8 +86,6 @@ 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@
......@@ -95,10 +93,10 @@ LIBMIKMOD_CFLAGS = @LIBMIKMOD_CFLAGS@
LIBMIKMOD_CONFIG = @LIBMIKMOD_CONFIG@
LIBMIKMOD_LDADD = @LIBMIKMOD_LDADD@
LIBMIKMOD_LIBS = @LIBMIKMOD_LIBS@
LIBOGGFLAC_CFLAGS = @LIBOGGFLAC_CFLAGS@
LIBOGGFLAC_LIBS = @LIBOGGFLAC_LIBS@
LIBTOOL = @LIBTOOL@
LN_S = @LN_S@
MAD_LIB = @MAD_LIB@
MAD_SUBDIR = @MAD_SUBDIR@
MP4FF_LIB = @MP4FF_LIB@
MP4FF_SUBDIR = @MP4FF_SUBDIR@
MPD_CFLAGS = @MPD_CFLAGS@
......@@ -108,6 +106,7 @@ OGG_CFLAGS = @OGG_CFLAGS@
OGG_LIBS = @OGG_LIBS@
PACKAGE = @PACKAGE@
PKGCONFIG = @PKGCONFIG@
PKG_CONFIG = @PKG_CONFIG@
RANLIB = @RANLIB@
RC = @RC@
SHOUTCONFIG = @SHOUTCONFIG@
......@@ -120,10 +119,10 @@ VORBIS_LIBS = @VORBIS_LIBS@
am__include = @am__include@
am__quote = @am__quote@
install_sh = @install_sh@
man_MANS = mpd.1
man_MANS = mpd.1 mpd.conf.5
docdir = $(prefix)/share/doc/$(PACKAGE)
doc_DATA = COMMANDS
EXTRA_DIST = mpdconf.example $(man_MANS) $(doc_DATA)
doc_DATA = COMMANDS mpdconf.example
EXTRA_DIST = $(man_MANS) $(doc_DATA)
subdir = doc
mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
CONFIG_HEADER = $(top_builddir)/config.h
......@@ -196,6 +195,49 @@ uninstall-man1:
echo " rm -f $(DESTDIR)$(man1dir)/$$inst"; \
rm -f $(DESTDIR)$(man1dir)/$$inst; \
done
man5dir = $(mandir)/man5
install-man5: $(man5_MANS) $(man_MANS)
@$(NORMAL_INSTALL)
$(mkinstalldirs) $(DESTDIR)$(man5dir)
@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.5*) 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 \
5*) ;; \
*) ext='5' ;; \
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)$(man5dir)/$$inst"; \
$(INSTALL_DATA) $$file $(DESTDIR)$(man5dir)/$$inst; \
done
uninstall-man5:
@$(NORMAL_UNINSTALL)
@list='$(man5_MANS) $(dist_man5_MANS) $(nodist_man5_MANS)'; \
l2='$(man_MANS) $(dist_man_MANS) $(nodist_man_MANS)'; \
for i in $$l2; do \
case "$$i" in \
*.5*) 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)$(man5dir)/$$inst"; \
rm -f $(DESTDIR)$(man5dir)/$$inst; \
done
docDATA_INSTALL = $(INSTALL_DATA)
install-docDATA: $(doc_DATA)
@$(NORMAL_INSTALL)
......@@ -248,7 +290,7 @@ check: check-am
all-am: Makefile $(MANS) $(DATA)
installdirs:
$(mkinstalldirs) $(DESTDIR)$(man1dir) $(DESTDIR)$(docdir)
$(mkinstalldirs) $(DESTDIR)$(man1dir) $(DESTDIR)$(man5dir) $(DESTDIR)$(docdir)
install: install-am
install-exec: install-exec-am
......@@ -296,7 +338,7 @@ install-exec-am:
install-info: install-info-am
install-man: install-man1
install-man: install-man1 install-man5
installcheck-am:
......@@ -310,18 +352,18 @@ mostlyclean-am: mostlyclean-generic mostlyclean-libtool
uninstall-am: uninstall-docDATA uninstall-info-am uninstall-man
uninstall-man: uninstall-man1
uninstall-man: uninstall-man1 uninstall-man5
.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
install-man5 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 uninstall-man5
# 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.
......
This diff is collapsed. Click to expand it.
......@@ -3,11 +3,12 @@
# Check the mpd man page, "man mpd".
##################### REQUIRED ###########################
port "6600"
music_directory "~/music"
playlist_directory "~/.mpd/playlists"
playlist_directory "~/music"
db_file "~/.mpd/mpd.db"
log_file "~/.mpd/mpd.log"
error_file "~/.mpd/mpd.error"
pid_file "~/.mpd/mpd.pid"
##########################################################
##########################################################
......@@ -16,26 +17,28 @@ error_file "~/.mpd/mpd.error"
################## AUDIO OUTPUT ##########################
#
# libao (ao_driver) supports any of the following:
# Refer to libao documentation for more information
#
audio_output {
# Use default settings
type "ao"
name "default ao output"
#
# use this if you want to use OSS audio output
# type "ao"
#audio_output {
# type "oss"
# name "my OSS sound card"
# driver "oss"
# options "dsp=/dev/dsp"
# device "/dev/dsp" # optional
# format "44100:16:2" #optional
#}
#
# use this if you want to use ALSA audio output
# type "ao"
#audio_output {
# type "alsa"
# name "my ALSA device"
# driver "alsa09"
# options "dev=hw:0,0"
} # end of audio_output "ao"
# device "hw:0,0" # optional
# format "44100:16:2" #optional
#}
#
# as a last resort, try using libao
#audio_output {
# type "ao"
# name "default ao output"
#}
#
#
# Set this if you have problems
# playing audio files.
......@@ -82,9 +85,9 @@ audio_output {
# bitrate "128"
# format "44100:16:1"
#
# Optional Paramters
# Optional Parameters
# user "source"
# description "here's my long descriptiion"
# description "here's my long description"
# genre "jazz"
#} # end of audio_output
#
......@@ -111,10 +114,6 @@ audio_output {
#################### OPTIONAL FILES ######################
#
# Location of DB file
#
#db_file "~/.mpd/mpd.db"
#
# The state file (if set) will be a file
# for storing all current information
# (playlist, playing/paused, etc...) from
......@@ -127,9 +126,9 @@ audio_output {
##########################################################
################# REPLAYGAIN #############################
################# Normalization ##########################
#
# Use Replay Gain (album or title)
# Use Replay Gain (album or track)
# http://www.replaygain.org
#
#replaygain "album"
......@@ -139,6 +138,13 @@ audio_output {
#
#replaygain_preamp "0"
#
# Normalization increases the amplitude of the audio
# waveform to the maximum level without introducing any
# distortion into the recording. This option will
# normalize when replaygain is not on, utilizing the
# CPU for calculation.
#
#volume_normalization "yes"
##########################################################
......@@ -173,7 +179,7 @@ audio_output {
# It is encouraged to run MPD as
# non-superuser. If you start mpd as root
# (for example, in an init script), set
# this value, then mpd will drop root priveleges
# this value, then mpd will drop root privileges
# and runs as the user specified.
#
#user "nobody"
......@@ -199,6 +205,17 @@ audio_output {
################ MISCELLANEOUS OPTIONS ###################
#
#port "6600"
#
# This determines what encoding ID3v1 tags should be converted from.
#
#id3v1_encoding "ISO-8859-1"
#
# This sets the metadata mpd will use, to disable all metadata, set to "none"
# NOTE: comments are disabled by default
#
#metadata_to_use "artist,album,title,genre,date,track,composer,performer,comment"
#
# This setting exists as precaution against attacks.
#
#max_playlist_length "16384"
......@@ -216,7 +233,7 @@ audio_output {
# No need to change these unless you know better.
#
#max_command_list_size "2048"
#max_output_buffer_size "2048"
#max_output_buffer_size "8192"
#
# This will make playlists compatible with normal music
# players.
......
bin_PROGRAMS = mpd
SUBDIRS = $(ID3_SUBDIR) $(MAD_SUBDIR) $(MP4FF_SUBDIR)
SUBDIRS = $(MP4FF_SUBDIR)
mpd_audioOutputs = \
audioOutputs/audioOutput_alsa.c \
audioOutputs/audioOutput_ao.c \
audioOutputs/audioOutput_oss.c \
audioOutputs/audioOutput_osx.c \
audioOutputs/audioOutput_pulse.c \
audioOutputs/audioOutput_mvp.c \
audioOutputs/audioOutput_shout.c
mpd_inputPlugins = \
inputPlugins/_flac_common.c \
inputPlugins/_ogg_common.c \
inputPlugins/oggflac_plugin.c \
inputPlugins/oggvorbis_plugin.c \
inputPlugins/aac_plugin.c \
inputPlugins/audiofile_plugin.c \
inputPlugins/flac_plugin.c \
inputPlugins/mod_plugin.c \
inputPlugins/mp3_plugin.c \
inputPlugins/mp4_plugin.c \
inputPlugins/ogg_plugin.c
inputPlugins/mpc_plugin.c
mpd_headers = \
......@@ -24,9 +32,13 @@ mpd_headers = \
charConv.h \
command.h \
conf.h \
dbUtils.h \
decode.h \
directory.h \
gcc.h \
inputPlugin.h \
inputPlugins/_flac_common.h \
inputPlugins/_ogg_common.h \
inputStream.h \
inputStream_file.h \
inputStream_http.h \
......@@ -38,6 +50,8 @@ mpd_headers = \
metadataChunk.h \
mpd_types.h \
myfprintf.h \
normalize.h \
compress.h \
outputBuffer.h \
path.h \
pcm_utils.h \
......@@ -48,10 +62,13 @@ mpd_headers = \
replayGain.h \
signal_check.h \
sig_handlers.h \
sllist.h \
song.h \
state_file.h \
stats.h \
tag.h \
tables.h \
tagTracker.h \
tree.h \
utf8.h \
utils.h \
volume.h
......@@ -67,6 +84,7 @@ mpd_SOURCES = \
charConv.c \
command.c \
conf.c \
dbUtils.c \
decode.c \
directory.c \
inputPlugin.c \
......@@ -81,6 +99,8 @@ mpd_SOURCES = \
main.c \
metadataChunk.c \
myfprintf.c \
normalize.c \
compress.c \
outputBuffer.c \
path.c \
pcm_utils.c \
......@@ -91,16 +111,30 @@ mpd_SOURCES = \
replayGain.c \
sig_handlers.c \
signal_check.c \
sllist.c \
song.c \
state_file.c \
stats.c \
tables.c \
tag.c \
tagTracker.c \
tree.c \
utils.c \
volume.c \
utf8.c
mpd_CFLAGS = $(MPD_CFLAGS)
mpd_LDADD = $(MPD_LIBS) $(ID3_LIB) $(MAD_LIB) $(MP4FF_LIB)
mpd_LDADD = $(MPD_LIBS) $(MP4FF_LIB)
DIST_SUBDIRS = mp4ff
# sparse is a semantic parser
# URL: git://www.kernel.org/pub/scm/devel/sparse/sparse.git
SPARSE = sparse
SPARSE_FLAGS =
sparse-check:
for i in $(mpd_SOURCES); \
do \
$(SPARSE) -I. $(mpd_CFLAGS) $(SPARSE_FLAGS) $(srcdir)/$$i || exit; \
done
DIST_SUBDIRS = mp4ff $(ID3_SUBDIR) $(MAD_SUBDIR)
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -28,21 +28,21 @@
#define AUDIO_AO_DRIVER_DEFAULT "default"
#define AUDIO_MAX_DEVICES 8
typedef struct _AudioFormat {
volatile mpd_sint8 channels;
volatile mpd_uint32 sampleRate;
volatile mpd_sint8 bits;
} AudioFormat;
size_t audio_device_count(void);
void copyAudioFormat(AudioFormat * dest, AudioFormat * src);
int cmpAudioFormat(AudioFormat * dest, AudioFormat * src);
void getOutputAudioFormat(AudioFormat * inFormat, AudioFormat * outFormat);
int parseAudioConfig(AudioFormat * audioFormat, char * conf);
int parseAudioConfig(AudioFormat * audioFormat, char *conf);
/* make sure initPlayerData is called before this function!! */
void initAudioConfig();
......@@ -55,7 +55,9 @@ void finishAudioDriver();
int openAudioDevice(AudioFormat * audioFormat);
int playAudio(char * playChunk,int size);
int playAudio(char *playChunk, int size);
void dropBufferedAudio();
void closeAudioDevice();
......@@ -67,10 +69,15 @@ void sendMetadataToAudioDevice(MpdTag * tag);
/* these functions are called in the main parent process while the child
process is busy playing to the audio */
int enableAudioDevice(FILE * fp, int device);
int enableAudioDevice(int fd, int device);
int disableAudioDevice(int fd, int device);
void printAudioDevices(int fd);
int disableAudioDevice(FILE * fp, int device);
void readAudioDevicesState(FILE *fp);
void printAudioDevices(FILE * fp);
void saveAudioDevicesState(FILE *fp);
void loadAudioDrivers();
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -26,53 +26,72 @@
#include "tag.h"
#include "conf.h"
#define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) \
AudioOutputPlugin plugin = { \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
};
typedef struct _AudioOutput AudioOutput;
typedef int (* AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
ConfigParam * param);
typedef int (*AudioOutputTestDefaultDeviceFunc) ();
typedef int (*AudioOutputInitDriverFunc) (AudioOutput * audioOutput,
ConfigParam * param);
typedef void (*AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
typedef void (* AudioOutputFinishDriverFunc) (AudioOutput * audioOutput);
typedef int (*AudioOutputOpenDeviceFunc) (AudioOutput * audioOutput);
typedef int (* AudioOutputOpenDeviceFunc) (AudioOutput * audioOutput,
AudioFormat * audioFormat);
typedef int (*AudioOutputPlayFunc) (AudioOutput * audioOutput,
char *playChunk, int size);
typedef int (* AudioOutputPlayFunc) (AudioOutput * audioOutput,
char * playChunk, int size);
typedef void (*AudioOutputDropBufferedAudioFunc) (AudioOutput * audioOutput);
typedef void (* AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
typedef void (*AudioOutputCloseDeviceFunc) (AudioOutput * audioOutput);
typedef void (* AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
MpdTag * tag);
typedef void (*AudioOutputSendMetadataFunc) (AudioOutput * audioOutput,
MpdTag * tag);
struct _AudioOutput {
int open;
char * name;
char * type;
AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc;
AudioOutputPlayFunc playFunc;
AudioOutputCloseDeviceFunc closeDeviceFunc;
char *name;
char *type;
AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc;
AudioOutputPlayFunc playFunc;
AudioOutputDropBufferedAudioFunc dropBufferedAudioFunc;
AudioOutputCloseDeviceFunc closeDeviceFunc;
AudioOutputSendMetadataFunc sendMetdataFunc;
int convertAudioFormat;
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
char * convBuffer;
AudioFormat reqAudioFormat;
char *convBuffer;
int convBufferLen;
int sameInAndOutFormats;
void * data;
void *data;
};
typedef struct _AudioOutputPlugin {
char * name;
AudioOutputInitDriverFunc initDriverFunc;
AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc;
AudioOutputPlayFunc playFunc;
AudioOutputCloseDeviceFunc closeDeviceFunc;
char *name;
AudioOutputTestDefaultDeviceFunc testDefaultDeviceFunc;
AudioOutputInitDriverFunc initDriverFunc;
AudioOutputFinishDriverFunc finishDriverFunc;
AudioOutputOpenDeviceFunc openDeviceFunc;
AudioOutputPlayFunc playFunc;
AudioOutputDropBufferedAudioFunc dropBufferedAudioFunc;
AudioOutputCloseDeviceFunc closeDeviceFunc;
AudioOutputSendMetadataFunc sendMetdataFunc;
} AudioOutputPlugin;
......@@ -82,12 +101,14 @@ void finishAudioOutputPlugins();
void loadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
void unloadAudioOutputPlugin(AudioOutputPlugin * audioOutputPlugin);
AudioOutput * newAudioOutput(ConfigParam * param);
int initAudioOutput(AudioOutput *, ConfigParam * param);
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat);
int playAudioOutput(AudioOutput * audioOutput, char * playChunk, int size);
int playAudioOutput(AudioOutput * audioOutput, char *playChunk, int size);
void dropBufferedAudioOutput(AudioOutput * audioOutput);
void closeAudioOutput(AudioOutput * audioOutput);
void finishAudioOutput(AudioOutput * audioOutput);
int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag);
void printAllOutputPluginTypes(FILE * fp);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -17,6 +17,9 @@
*/
#include "../audioOutput.h"
#ifdef HAVE_AO
#include "../conf.h"
#include "../log.h"
......@@ -31,122 +34,120 @@ static int driverInitCount = 0;
typedef struct _AoData {
int writeSize;
int driverId;
ao_option * options;
ao_device * device;
ao_option *options;
ao_device *device;
} AoData;
static AoData * newAoData() {
AoData * ret = malloc(sizeof(AoData));
static AoData *newAoData(void)
{
AoData *ret = malloc(sizeof(AoData));
ret->device = NULL;
ret->options = NULL;
return ret;
}
static void audioOutputAo_error() {
if(errno==AO_ENOTLIVE) {
static void audioOutputAo_error(void)
{
if (errno == AO_ENOTLIVE) {
ERROR("not a live ao device\n");
}
else if(errno==AO_EOPENDEVICE) {
} else if (errno == AO_EOPENDEVICE) {
ERROR("not able to open audio device\n");
}
else if(errno==AO_EBADOPTION) {
} else if (errno == AO_EBADOPTION) {
ERROR("bad driver option\n");
}
}
static int audioOutputAo_initDriver(AudioOutput * audioOutput,
ConfigParam * param)
ConfigParam * param)
{
ao_info * ai;
char * dup;
char * stk1;
char * stk2;
char * n1;
char * key;
char * value;
char * test;
AoData * ad = newAoData();
BlockParam * blockParam;
ao_info *ai;
char *dup;
char *stk1;
char *stk2;
char *n1;
char *key;
char *value;
char *test;
AoData *ad = newAoData();
BlockParam *blockParam;
audioOutput->data = ad;
if((blockParam = getBlockParam(param, "write_size"))) {
if ((blockParam = getBlockParam(param, "write_size"))) {
ad->writeSize = strtol(blockParam->value, &test, 10);
if (*test!='\0') {
if (*test != '\0') {
ERROR("\"%s\" is not a valid write size at line %i\n",
blockParam->value, blockParam->line);
blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
}
}
else ad->writeSize = 1024;
} else
ad->writeSize = 1024;
if(driverInitCount == 0) {
if (driverInitCount == 0) {
ao_initialize();
}
driverInitCount++;
blockParam = getBlockParam(param, "driver");
if(!blockParam || 0 == strcmp(blockParam->value,"default")) {
if (!blockParam || 0 == strcmp(blockParam->value, "default")) {
ad->driverId = ao_default_driver_id();
}
else if((ad->driverId =
ao_driver_id(blockParam->value))<0) {
} else if ((ad->driverId = ao_driver_id(blockParam->value)) < 0) {
ERROR("\"%s\" is not a valid ao driver at line %i\n",
blockParam->value, blockParam->line);
blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
}
if((ai = ao_driver_info(ad->driverId))==NULL) {
if ((ai = ao_driver_info(ad->driverId)) == NULL) {
ERROR("problems getting driver info for device defined at "
"line %i\n", param->line);
"line %i\n", param->line);
ERROR("you may not have permission to the audio device\n");
exit(EXIT_FAILURE);
}
DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
audioOutput->name);
DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
audioOutput->name);
blockParam = getBlockParam(param, "options");
if(blockParam) {
if (blockParam) {
dup = strdup(blockParam->value);
}
else dup = strdup("");
} else
dup = strdup("");
if(strlen(dup)) {
if (strlen(dup)) {
stk1 = NULL;
n1 = strtok_r(dup,";",&stk1);
while(n1) {
n1 = strtok_r(dup, ";", &stk1);
while (n1) {
stk2 = NULL;
key = strtok_r(n1,"=",&stk2);
if(!key) {
key = strtok_r(n1, "=", &stk2);
if (!key) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
/*found = 0;
for(i=0;i<ai->option_count;i++) {
if(strcmp(ai->options[i],key)==0) {
found = 1;
break;
}
}
if(!found) {
ERROR("\"%s\" is not an option for "
"\"%s\" ao driver\n",key,
ai->short_name);
exit(EXIT_FAILURE);
}*/
value = strtok_r(NULL,"",&stk2);
if(!value) {
for(i=0;i<ai->option_count;i++) {
if(strcmp(ai->options[i],key)==0) {
found = 1;
break;
}
}
if(!found) {
ERROR("\"%s\" is not an option for "
"\"%s\" ao driver\n",key,
ai->short_name);
exit(EXIT_FAILURE);
} */
value = strtok_r(NULL, "", &stk2);
if (!value) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
ao_append_option(&ad->options,key,value);
n1 = strtok_r(NULL,";",&stk1);
ao_append_option(&ad->options, key, value);
n1 = strtok_r(NULL, ";", &stk1);
}
}
free(dup);
......@@ -154,24 +155,33 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
return 0;
}
static void freeAoData(AoData * ad) {
static void freeAoData(AoData * ad)
{
ao_free_options(ad->options);
free(ad);
}
static void audioOutputAo_finishDriver(AudioOutput * audioOutput) {
AoData * ad = (AoData *)audioOutput->data;
static void audioOutputAo_finishDriver(AudioOutput * audioOutput)
{
AoData *ad = (AoData *) audioOutput->data;
freeAoData(ad);
driverInitCount--;
if(driverInitCount == 0) ao_shutdown();
if (driverInitCount == 0)
ao_shutdown();
}
static void audioOutputAo_dropBufferedAudio(AudioOutput * audioOutput)
{
/* not supported by libao */
}
static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
AoData * ad = (AoData *) audioOutput->data;
static void audioOutputAo_closeDevice(AudioOutput * audioOutput)
{
AoData *ad = (AoData *) audioOutput->data;
if(ad->device) {
if (ad->device) {
ao_close(ad->device);
ad->device = NULL;
}
......@@ -179,63 +189,71 @@ static void audioOutputAo_closeDevice(AudioOutput * audioOutput) {
audioOutput->open = 0;
}
static int audioOutputAo_openDevice(AudioOutput * audioOutput,
AudioFormat * audioFormat)
static int audioOutputAo_openDevice(AudioOutput * audioOutput)
{
ao_sample_format format;
AoData * ad = (AoData *)audioOutput->data;
AoData *ad = (AoData *) audioOutput->data;
if(ad->device) {
if (ad->device) {
audioOutputAo_closeDevice(audioOutput);
}
format.bits = audioFormat->bits;
format.rate = audioFormat->sampleRate;
format.bits = audioOutput->outAudioFormat.bits;
format.rate = audioOutput->outAudioFormat.sampleRate;
format.byte_format = AO_FMT_NATIVE;
format.channels = audioFormat->channels;
format.channels = audioOutput->outAudioFormat.channels;
ad->device = ao_open_live(ad->driverId, &format, ad->options);
if(ad->device==NULL) return -1;
if (ad->device == NULL)
return -1;
audioOutput->open = 1;
return 0;
}
static int audioOutputAo_play(AudioOutput * audioOutput, char * playChunk,
int size)
static int audioOutputAo_play(AudioOutput * audioOutput, char *playChunk,
int size)
{
int send;
AoData * ad = (AoData *)audioOutput->data;
AoData *ad = (AoData *) audioOutput->data;
if(ad->device==NULL) return -1;
while(size>0) {
if (ad->device == NULL)
return -1;
while (size > 0) {
send = ad->writeSize > size ? size : ad->writeSize;
if(ao_play(ad->device, playChunk, send)==0) {
if (ao_play(ad->device, playChunk, send) == 0) {
audioOutputAo_error();
ERROR("closing audio device due to write error\n");
audioOutputAo_closeDevice(audioOutput);
return -1;
}
playChunk+=send;
size-=send;
playChunk += send;
size -= send;
}
return 0;
}
AudioOutputPlugin aoPlugin =
{
AudioOutputPlugin aoPlugin = {
"ao",
NULL,
audioOutputAo_initDriver,
audioOutputAo_finishDriver,
audioOutputAo_openDevice,
audioOutputAo_play,
audioOutputAo_dropBufferedAudio,
audioOutputAo_closeDevice,
NULL /* sendMetadataFunc */
NULL, /* sendMetadataFunc */
};
#else
#include <stdio.h>
DISABLED_AUDIO_OUTPUT_PLUGIN(aoPlugin)
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* Media MVP audio output based on code from MVPMC project:
* http://mvpmc.sourceforge.net/
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../audioOutput.h"
#include <stdlib.h>
#ifdef HAVE_MVP
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/ioctl.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
typedef struct {
unsigned long dsp_status;
unsigned long stream_decode_type;
unsigned long sample_rate;
unsigned long bit_rate;
unsigned long raw[64 / sizeof(unsigned long)];
} aud_status_t;
#define MVP_SET_AUD_STOP _IOW('a',1,int)
#define MVP_SET_AUD_PLAY _IOW('a',2,int)
#define MVP_SET_AUD_PAUSE _IOW('a',3,int)
#define MVP_SET_AUD_UNPAUSE _IOW('a',4,int)
#define MVP_SET_AUD_SRC _IOW('a',5,int)
#define MVP_SET_AUD_MUTE _IOW('a',6,int)
#define MVP_SET_AUD_BYPASS _IOW('a',8,int)
#define MVP_SET_AUD_CHANNEL _IOW('a',9,int)
#define MVP_GET_AUD_STATUS _IOR('a',10,aud_status_t)
#define MVP_SET_AUD_VOLUME _IOW('a',13,int)
#define MVP_GET_AUD_VOLUME _IOR('a',14,int)
#define MVP_SET_AUD_STREAMTYPE _IOW('a',15,int)
#define MVP_SET_AUD_FORMAT _IOW('a',16,int)
#define MVP_GET_AUD_SYNC _IOR('a',21,pts_sync_data_t*)
#define MVP_SET_AUD_STC _IOW('a',22,long long int *)
#define MVP_SET_AUD_SYNC _IOW('a',23,int)
#define MVP_SET_AUD_END_STREAM _IOW('a',25,int)
#define MVP_SET_AUD_RESET _IOW('a',26,int)
#define MVP_SET_AUD_DAC_CLK _IOW('a',27,int)
#define MVP_GET_AUD_REGS _IOW('a',28,aud_ctl_regs_t*)
typedef struct _MvpData {
int fd;
} MvpData;
static int pcmfrequencies[][3] = {
{9, 8000, 32000},
{10, 11025, 44100},
{11, 12000, 48000},
{1, 16000, 32000},
{2, 22050, 44100},
{3, 24000, 48000},
{5, 32000, 32000},
{0, 44100, 44100},
{7, 48000, 48000},
{13, 64000, 32000},
{14, 88200, 44100},
{15, 96000, 48000}
};
static int numfrequencies = sizeof(pcmfrequencies) / 12;
static int mvp_testDefault(void)
{
int fd;
fd = open("/dev/adec_pcm", O_WRONLY);
if (fd) {
close(fd);
return 0;
}
WARNING("Error opening PCM device \"/dev/adec_pcm\": %s\n",
strerror(errno));
return -1;
}
static int mvp_initDriver(AudioOutput * audioOutput, ConfigParam * param)
{
MvpData *md = malloc(sizeof(MvpData));
md->fd = -1;
audioOutput->data = md;
return 0;
}
static void mvp_finishDriver(AudioOutput * audioOutput)
{
MvpData *md = audioOutput->data;
free(md);
}
static int mvp_setPcmParams(MvpData * md, unsigned long rate, int channels,
int big_endian, int bits)
{
int iloop;
int mix[5];
if (channels == 1)
mix[0] = 1;
else if (channels == 2)
mix[0] = 0;
else
return -1;
/* 0,1=24bit(24) , 2,3=16bit */
if (bits == 16)
mix[1] = 2;
else if (bits == 24)
mix[1] = 0;
else
return -1;
mix[3] = 0; /* stream type? */
if (big_endian == 1)
mix[4] = 1;
else if (big_endian == 0)
mix[4] = 0;
else
return -1;
/*
* if there is an exact match for the frequency, use it.
*/
for (iloop = 0; iloop < numfrequencies; iloop++) {
if (rate == pcmfrequencies[iloop][1]) {
mix[2] = pcmfrequencies[iloop][0];
break;
}
}
if (iloop >= numfrequencies) {
ERROR("Can not find suitable output frequency for %ld\n", rate);
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
ERROR("Can not set audio format\n");
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_SYNC, 2) != 0) {
ERROR("Can not set audio sync\n");
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_PLAY, 0) < 0) {
ERROR("Can not set audio play mode\n");
return -1;
}
return 0;
}
static int mvp_openDevice(AudioOutput * audioOutput)
{
long long int stc = 0;
MvpData *md = audioOutput->data;
AudioFormat *audioFormat = &audioOutput->outAudioFormat;
int mix[5] = { 0, 2, 7, 1, 0 };
if ((md->fd = open("/dev/adec_pcm", O_RDWR | O_NONBLOCK)) < 0) {
ERROR("Error opening /dev/adec_pcm: %s\n", strerror(errno));
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_SRC, 1) < 0) {
ERROR("Error setting audio source: %s\n", strerror(errno));
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_STREAMTYPE, 0) < 0) {
ERROR("Error setting audio streamtype: %s\n", strerror(errno));
return -1;
}
if (ioctl(md->fd, MVP_SET_AUD_FORMAT, &mix) < 0) {
ERROR("Error setting audio format: %s\n", strerror(errno));
return -1;
}
ioctl(md->fd, MVP_SET_AUD_STC, &stc);
if (ioctl(md->fd, MVP_SET_AUD_BYPASS, 1) < 0) {
ERROR("Error setting audio streamtype: %s\n", strerror(errno));
return -1;
}
#ifdef WORDS_BIGENDIAN
mvp_setPcmParams(md, audioFormat->sampleRate, audioFormat->channels, 0,
audioFormat->bits);
#else
mvp_setPcmParams(md, audioFormat->sampleRate, audioFormat->channels, 1,
audioFormat->bits);
#endif
audioOutput->open = 1;
return 0;
}
static void mvp_closeDevice(AudioOutput * audioOutput)
{
MvpData *md = audioOutput->data;
if (md->fd >= 0)
close(md->fd);
md->fd = -1;
audioOutput->open = 0;
}
static void mvp_dropBufferedAudio(AudioOutput * audioOutput)
{
MvpData *md = audioOutput->data;
if (md->fd >= 0) {
ioctl(md->fd, MVP_SET_AUD_RESET, 0x11);
close(md->fd);
md->fd = -1;
audioOutput->open = 0;
}
}
static int mvp_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
{
MvpData *md = audioOutput->data;
int ret;
/* reopen the device since it was closed by dropBufferedAudio */
if (md->fd < 0)
mvp_openDevice(audioOutput);
while (size > 0) {
ret = write(md->fd, playChunk, size);
if (ret < 0) {
if (errno == EINTR)
continue;
ERROR("closing mvp PCM device due to write error: "
"%s\n", strerror(errno));
mvp_closeDevice(audioOutput);
return -1;
}
playChunk += ret;
size -= ret;
}
return 0;
}
AudioOutputPlugin mvpPlugin = {
"mvp",
mvp_testDefault,
mvp_initDriver,
mvp_finishDriver,
mvp_openDevice,
mvp_playAudio,
mvp_dropBufferedAudio,
mvp_closeDevice,
NULL, /* sendMetadataFunc */
};
#else /* HAVE_MVP */
DISABLED_AUDIO_OUTPUT_PLUGIN(mvpPlugin)
#endif /* HAVE_MVP */
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* 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 "../audioOutput.h"
#ifdef HAVE_OSX
#include <AudioUnit/AudioUnit.h>
#include <stdlib.h>
#include <pthread.h>
#include "../log.h"
#include "../utils.h"
typedef struct _OsxData {
AudioUnit au;
pthread_mutex_t mutex;
pthread_cond_t condition;
char *buffer;
int bufferSize;
int pos;
int len;
int started;
} OsxData;
static OsxData *newOsxData()
{
OsxData *ret = malloc(sizeof(OsxData));
pthread_mutex_init(&ret->mutex, NULL);
pthread_cond_init(&ret->condition, NULL);
ret->pos = 0;
ret->len = 0;
ret->started = 0;
ret->buffer = NULL;
ret->bufferSize = 0;
return ret;
}
static int osx_testDefault()
{
/*AudioUnit au;
ComponentDescription desc;
Component comp;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_Output;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = FindNextComponent(NULL, &desc);
if(!comp) {
ERROR("Unable to open default OS X defice\n");
return -1;
}
if(OpenAComponent(comp, &au) != noErr) {
ERROR("Unable to open default OS X defice\n");
return -1;
}
CloseComponent(au); */
return 0;
}
static int osx_initDriver(AudioOutput * audioOutput, ConfigParam * param)
{
OsxData *od = newOsxData();
audioOutput->data = od;
return 0;
}
static void freeOsxData(OsxData * od)
{
if (od->buffer)
free(od->buffer);
pthread_mutex_destroy(&od->mutex);
pthread_cond_destroy(&od->condition);
free(od);
}
static void osx_finishDriver(AudioOutput * audioOutput)
{
OsxData *od = (OsxData *) audioOutput->data;
freeOsxData(od);
}
static void osx_dropBufferedAudio(AudioOutput * audioOutput)
{
OsxData *od = (OsxData *) audioOutput->data;
pthread_mutex_lock(&od->mutex);
od->len = 0;
pthread_mutex_unlock(&od->mutex);
}
static void osx_closeDevice(AudioOutput * audioOutput)
{
OsxData *od = (OsxData *) audioOutput->data;
pthread_mutex_lock(&od->mutex);
while (od->len) {
pthread_cond_wait(&od->condition, &od->mutex);
}
pthread_mutex_unlock(&od->mutex);
if (od->started) {
AudioOutputUnitStop(od->au);
od->started = 0;
}
CloseComponent(od->au);
AudioUnitUninitialize(od->au);
audioOutput->open = 0;
}
static OSStatus osx_render(void *vdata,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber, UInt32 inNumberFrames,
AudioBufferList * bufferList)
{
OsxData *od = (OsxData *) vdata;
AudioBuffer *buffer = &bufferList->mBuffers[0];
int bufferSize = buffer->mDataByteSize;
int bytesToCopy;
int curpos = 0;
/*DEBUG("osx_render: enter : %i\n", (int)bufferList->mNumberBuffers);
DEBUG("osx_render: ioActionFlags: %p\n", ioActionFlags);
if(ioActionFlags) {
if(*ioActionFlags & kAudioUnitRenderAction_PreRender) {
DEBUG("prerender\n");
}
if(*ioActionFlags & kAudioUnitRenderAction_PostRender) {
DEBUG("post render\n");
}
if(*ioActionFlags & kAudioUnitRenderAction_OutputIsSilence) {
DEBUG("post render\n");
}
if(*ioActionFlags & kAudioOfflineUnitRenderAction_Preflight) {
DEBUG("prefilight\n");
}
if(*ioActionFlags & kAudioOfflineUnitRenderAction_Render) {
DEBUG("render\n");
}
if(*ioActionFlags & kAudioOfflineUnitRenderAction_Complete) {
DEBUG("complete\n");
}
} */
/* while(bufferSize) {
DEBUG("osx_render: lock\n"); */
pthread_mutex_lock(&od->mutex);
/*
DEBUG("%i:%i\n", bufferSize, od->len);
while(od->go && od->len < bufferSize &&
od->len < od->bufferSize)
{
DEBUG("osx_render: wait\n");
pthread_cond_wait(&od->condition, &od->mutex);
}
*/
bytesToCopy = od->len < bufferSize ? od->len : bufferSize;
bufferSize = bytesToCopy;
od->len -= bytesToCopy;
if (od->pos + bytesToCopy > od->bufferSize) {
int bytes = od->bufferSize - od->pos;
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytes);
od->pos = 0;
curpos += bytes;
bytesToCopy -= bytes;
}
memcpy(buffer->mData + curpos, od->buffer + od->pos, bytesToCopy);
od->pos += bytesToCopy;
curpos += bytesToCopy;
if (od->pos >= od->bufferSize)
od->pos = 0;
/* DEBUG("osx_render: unlock\n"); */
pthread_mutex_unlock(&od->mutex);
pthread_cond_signal(&od->condition);
/* } */
buffer->mDataByteSize = bufferSize;
if (!bufferSize) {
my_usleep(1000);
}
/* DEBUG("osx_render: leave\n"); */
return 0;
}
static int osx_openDevice(AudioOutput * audioOutput)
{
OsxData *od = (OsxData *) audioOutput->data;
ComponentDescription desc;
Component comp;
AURenderCallbackStruct callback;
AudioFormat *audioFormat = &audioOutput->outAudioFormat;
AudioStreamBasicDescription streamDesc;
desc.componentType = kAudioUnitType_Output;
desc.componentSubType = kAudioUnitSubType_DefaultOutput;
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
desc.componentFlags = 0;
desc.componentFlagsMask = 0;
comp = FindNextComponent(NULL, &desc);
if (comp == 0) {
ERROR("Error finding OS X component\n");
return -1;
}
if (OpenAComponent(comp, &od->au) != noErr) {
ERROR("Unable to open OS X component\n");
return -1;
}
if (AudioUnitInitialize(od->au) != 0) {
CloseComponent(od->au);
ERROR("Unable to initialuze OS X audio unit\n");
return -1;
}
callback.inputProc = osx_render;
callback.inputProcRefCon = od;
if (AudioUnitSetProperty(od->au, kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input, 0,
&callback, sizeof(callback)) != 0) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
ERROR("unable to set callbak for OS X audio unit\n");
return -1;
}
streamDesc.mSampleRate = audioFormat->sampleRate;
streamDesc.mFormatID = kAudioFormatLinearPCM;
streamDesc.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger |
kLinearPCMFormatFlagIsBigEndian;
streamDesc.mBytesPerPacket =
audioFormat->channels * audioFormat->bits / 8;
streamDesc.mFramesPerPacket = 1;
streamDesc.mBytesPerFrame = streamDesc.mBytesPerPacket;
streamDesc.mChannelsPerFrame = audioFormat->channels;
streamDesc.mBitsPerChannel = audioFormat->bits;
if (AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0,
&streamDesc, sizeof(streamDesc)) != 0) {
AudioUnitUninitialize(od->au);
CloseComponent(od->au);
ERROR("Unable to set format on OS X device\n");
return -1;
}
/* create a buffer of 1s */
od->bufferSize = (audioFormat->sampleRate) *
(audioFormat->bits >> 3) * (audioFormat->channels);
od->buffer = realloc(od->buffer, od->bufferSize);
od->pos = 0;
od->len = 0;
audioOutput->open = 1;
return 0;
}
static int osx_play(AudioOutput * audioOutput, char *playChunk, int size)
{
OsxData *od = (OsxData *) audioOutput->data;
int bytesToCopy;
int curpos;
/* DEBUG("osx_play: enter\n"); */
if (!od->started) {
int err;
od->started = 1;
err = AudioOutputUnitStart(od->au);
if (err) {
ERROR("unable to start audio output: %i\n", err);
return -1;
}
}
pthread_mutex_lock(&od->mutex);
while (size) {
/* DEBUG("osx_play: lock\n"); */
curpos = od->pos + od->len;
if (curpos >= od->bufferSize)
curpos -= od->bufferSize;
bytesToCopy = od->bufferSize < size ? od->bufferSize : size;
while (od->len > od->bufferSize - bytesToCopy) {
/* DEBUG("osx_play: wait\n"); */
pthread_cond_wait(&od->condition, &od->mutex);
}
bytesToCopy = od->bufferSize - od->len;
bytesToCopy = bytesToCopy < size ? bytesToCopy : size;
size -= bytesToCopy;
od->len += bytesToCopy;
if (curpos + bytesToCopy > od->bufferSize) {
int bytes = od->bufferSize - curpos;
memcpy(od->buffer + curpos, playChunk, bytes);
curpos = 0;
playChunk += bytes;
bytesToCopy -= bytes;
}
memcpy(od->buffer + curpos, playChunk, bytesToCopy);
curpos += bytesToCopy;
playChunk += bytesToCopy;
}
/* DEBUG("osx_play: unlock\n"); */
pthread_mutex_unlock(&od->mutex);
/* DEBUG("osx_play: leave\n"); */
return 0;
}
AudioOutputPlugin osxPlugin = {
"osx",
osx_testDefault,
osx_initDriver,
osx_finishDriver,
osx_openDevice,
osx_play,
osx_dropBufferedAudio,
osx_closeDevice,
NULL, /* sendMetadataFunc */
};
#else
#include <stdio.h>
DISABLED_AUDIO_OUTPUT_PLUGIN(osxPlugin)
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* 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 "../audioOutput.h"
#include <stdlib.h>
#ifdef HAVE_PULSE
#include "../conf.h"
#include "../log.h"
#include <string.h>
#include <time.h>
#include <pulse/simple.h>
#include <pulse/error.h>
#define MPD_PULSE_NAME "mpd"
#define CONN_ATTEMPT_INTERVAL 60
typedef struct _PulseData {
pa_simple *s;
char *server;
char *sink;
int connAttempts;
time_t lastAttempt;
} PulseData;
static PulseData *newPulseData(void)
{
PulseData *ret;
ret = malloc(sizeof(PulseData));
ret->s = NULL;
ret->server = NULL;
ret->sink = NULL;
ret->connAttempts = 0;
ret->lastAttempt = 0;
return ret;
}
static void freePulseData(PulseData * pd)
{
if (pd->server)
free(pd->server);
if (pd->sink)
free(pd->sink);
free(pd);
}
static int pulse_initDriver(AudioOutput * audioOutput, ConfigParam * param)
{
BlockParam *server = NULL;
BlockParam *sink = NULL;
PulseData *pd;
if (param) {
server = getBlockParam(param, "server");
sink = getBlockParam(param, "sink");
}
pd = newPulseData();
pd->server = server ? strdup(server->value) : NULL;
pd->sink = sink ? strdup(sink->value) : NULL;
audioOutput->data = pd;
return 0;
}
static void pulse_finishDriver(AudioOutput * audioOutput)
{
freePulseData((PulseData *) audioOutput->data);
}
static int pulse_testDefault(void)
{
pa_simple *s;
pa_sample_spec ss;
int error;
ss.format = PA_SAMPLE_S16NE;
ss.rate = 44100;
ss.channels = 2;
s = pa_simple_new(NULL, MPD_PULSE_NAME, PA_STREAM_PLAYBACK, NULL,
MPD_PULSE_NAME, &ss, NULL, NULL, &error);
if (!s) {
WARNING("Cannot connect to default PulseAudio server: %s\n",
pa_strerror(error));
return -1;
}
pa_simple_free(s);
return 0;
}
static int pulse_openDevice(AudioOutput * audioOutput)
{
PulseData *pd;
AudioFormat *audioFormat;
pa_sample_spec ss;
time_t t;
int error;
t = time(NULL);
pd = audioOutput->data;
audioFormat = &audioOutput->outAudioFormat;
if (pd->connAttempts != 0 &&
(t - pd->lastAttempt) < CONN_ATTEMPT_INTERVAL)
return -1;
pd->connAttempts++;
pd->lastAttempt = t;
if (audioFormat->bits != 16) {
ERROR("PulseAudio doesn't support %i bit audio\n",
audioFormat->bits);
return -1;
}
ss.format = PA_SAMPLE_S16NE;
ss.rate = audioFormat->sampleRate;
ss.channels = audioFormat->channels;
pd->s = pa_simple_new(pd->server, MPD_PULSE_NAME, PA_STREAM_PLAYBACK,
pd->sink, audioOutput->name, &ss, NULL, NULL,
&error);
if (!pd->s) {
ERROR("Cannot connect to server in PulseAudio output "
"\"%s\" (attempt %i): %s\n", audioOutput->name,
pd->connAttempts, pa_strerror(error));
return -1;
}
pd->connAttempts = 0;
audioOutput->open = 1;
DEBUG("PulseAudio output \"%s\" connected and playing %i bit, %i "
"channel audio at %i Hz\n", audioOutput->name, audioFormat->bits,
audioFormat->channels, audioFormat->sampleRate);
return 0;
}
static void pulse_dropBufferedAudio(AudioOutput * audioOutput)
{
PulseData *pd;
int error;
pd = audioOutput->data;
if (pa_simple_flush(pd->s, &error) < 0)
WARNING("Flush failed in PulseAudio output \"%s\": %s\n",
audioOutput->name, pa_strerror(error));
}
static void pulse_closeDevice(AudioOutput * audioOutput)
{
PulseData *pd;
pd = audioOutput->data;
if (pd->s) {
pa_simple_drain(pd->s, NULL);
pa_simple_free(pd->s);
}
audioOutput->open = 0;
}
static int pulse_playAudio(AudioOutput * audioOutput, char *playChunk, int size)
{
PulseData *pd;
int error;
pd = audioOutput->data;
if (pa_simple_write(pd->s, playChunk, size, &error) < 0) {
ERROR("PulseAudio output \"%s\" disconnecting due to write "
"error: %s\n", audioOutput->name, pa_strerror(error));
pulse_closeDevice(audioOutput);
return -1;
}
return 0;
}
AudioOutputPlugin pulsePlugin = {
"pulse",
pulse_testDefault,
pulse_initDriver,
pulse_finishDriver,
pulse_openDevice,
pulse_playAudio,
pulse_dropBufferedAudio,
pulse_closeDevice,
NULL, /* sendMetadataFunc */
};
#else /* HAVE_PULSE */
DISABLED_AUDIO_OUTPUT_PLUGIN(pulsePlugin)
#endif /* HAVE_PULSE */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -21,102 +21,107 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int buffer2array(char * origBuffer, char *** array) {
int quotes = 0;
int count = 0;
int i;
int curr;
int * beginArray;
char * buffer = strdup(origBuffer);
int bufferLength = strlen(buffer);
char * markArray = malloc(sizeof(char)*(bufferLength+1));
for(curr=0;curr<bufferLength;curr++) {
if(!quotes && (buffer[curr]==' ' || buffer[curr]=='\t') ) {
markArray[curr] = '0';
}
else if(buffer[curr] == '\"') {
if(curr>0 && buffer[curr-1]!='\\') {
quotes = quotes?0:1;
markArray[curr] = '0';
}
else {
markArray[curr] = '1';
}
}
else {
markArray[curr] = '1';
}
if(markArray[curr]=='1') {
if(curr>0) {
if(markArray[curr-1]=='0') {
count++;
}
}
else {
count++;
}
}
}
markArray[bufferLength] = '\0';
if(!count) {
free(buffer);
free(markArray);
return count;
}
inline static
int
isWhiteSpace(char c)
{
return (c == ' ' || c == '\t');
}
beginArray = malloc(sizeof(int)*count);
(*array) = malloc(sizeof(char *)*count);
count = 0;
for(curr=0;curr<bufferLength;curr++) {
if(markArray[curr]=='1') {
if(curr>0) {
if(markArray[curr-1]=='0') {
beginArray[count++] = curr;
}
}
else {
beginArray[count++] = curr;
}
}
else {
buffer[curr] = '\0';
}
}
int buffer2array(char *buffer, char *array[], const int max)
{
int i = 0;
char *c = buffer;
for(i=0;i<count;i++) {
int len = strlen(buffer+beginArray[i])+1;
int arrayCurr = 0;
(*array)[i] = malloc(sizeof(char)*len);
for(curr=beginArray[i];buffer[curr]!='\0';curr++) {
if(buffer[curr]=='\\') {
if(buffer[curr+1]!='\0') {
curr++;
}
while (*c != '\0' && i < max) {
if (*c == '\"') {
int escape = 0;
array[i++] = ++c;
while (*c != '\0') {
if (*c == '\"') {
if (escape) {
memmove(c - 1, c,
strlen(c) + 1);
if (*c == '"')
break;
} else {
*(c++) = '\0';
break;
}
} else if (*c == '\\' && escape)
memmove(c - 1, c, strlen(c) + 1);
escape = (*(c++) != '\\') ? 0 : !escape;
}
(*array)[i][arrayCurr++] = buffer[curr];
} else {
while (isWhiteSpace(*c))
++c;
array[i++] = c++;
if (*c == '\0')
return i;
while (!isWhiteSpace(*c) && *c != '\0')
++c;
}
(*array)[i][arrayCurr] = '\0';
if (*c == '\0')
return i;
*(c++) = '\0';
while (isWhiteSpace(*c))
++c;
}
return i;
}
free(markArray);
free(beginArray);
free(buffer);
#ifdef UNIT_TEST
return count;
}
#include <stdio.h>
#include <string.h>
#include <assert.h>
void freeArgArray(char ** array, int argArrayLength) {
int i;
int main()
{
char *a[4] = { NULL };
char *b;
int i, max;
if(argArrayLength==0) return;
b = strdup("lsinfo \"/some/dir/name \\\"test\\\"\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("/some/dir/name \"test\"", a[1]) );
assert( !a[2] );
for(i=0;i<argArrayLength;i++) {
free(array[i]);
}
free(array);
b = strdup("lsinfo \"/some/dir/name \\\"test\\\" something else\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("/some/dir/name \"test\" something else", a[1]) );
assert( !a[2] );
b = strdup("lsinfo \"/some/dir\\\\name\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("/some/dir\\name", a[1]) );
assert( !a[2] );
b = strdup("lsinfo \"/some/dir name\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("/some/dir name", a[1]) );
assert( !a[2] );
b = strdup("lsinfo \"\\\"/some/dir\\\"\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("\"/some/dir\"", a[1]) );
assert( !a[2] );
b = strdup("lsinfo \"\\\"/some/dir\\\" x\"");
max = buffer2array(b, a, 4);
assert( !strcmp("lsinfo", a[0]) );
assert( !strcmp("\"/some/dir\" x", a[1]) );
assert( !a[2] );
return 0;
}
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -21,8 +21,12 @@
#include "../config.h"
int buffer2array(char * buffer, char *** array);
void freeArgArray(char ** array, int argArrayLength);
/* tokenizes up to max elements in buffer (a null-terminated string) and
* stores the result in array (which must be capable of holding up to
* max elements). Tokenization is based on C string quoting rules.
* The arguments buffer and array are modified.
* Returns the number of elements tokenized.
*/
int buffer2array(char *buffer, char *array[], const int max);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -29,49 +29,60 @@
iconv_t char_conv_iconv;
#endif
char * char_conv_to = NULL;
char * char_conv_from = NULL;
char *char_conv_to = NULL;
char *char_conv_from = NULL;
mpd_sint8 char_conv_same = 0;
mpd_sint8 char_conv_use_iconv = 0;
/* 1 is to use latin1ToUtf8
0 is not to use latin1/utf8 converter
-1 is to use utf8ToLatin1*/
-1 is to use utf8ToLatin1*/
mpd_sint8 char_conv_latin1ToUtf8 = 0;
#define BUFFER_SIZE 1024
int setCharSetConversion(char * to, char * from) {
if(char_conv_to && strcmp(to,char_conv_to)==0 &&
char_conv_from && strcmp(from,char_conv_from)==0)
{
return 0;
static void closeCharSetConversion();
int setCharSetConversion(char *to, char *from)
{
if (char_conv_to && char_conv_from) {
if (char_conv_latin1ToUtf8 &&
!strcmp(from, char_conv_to) &&
!strcmp(to, char_conv_from)) {
char *swap = char_conv_from;
char_conv_from = char_conv_to;
char_conv_to = swap;
char_conv_latin1ToUtf8 *= -1;
return 0;
} else if (!strcmp(to, char_conv_to) &&
!strcmp(from,char_conv_from)) {
return 0;
}
}
closeCharSetConversion();
if(0==strcmp(to,from)) {
if (0 == strcmp(to, from)) {
char_conv_same = 1;
char_conv_to = strdup(to);
char_conv_from = strdup(from);
return 0;
}
if(strcmp(to,"UTF-8")==0 && strcmp(from,"ISO-8859-1")==0) {
if (strcmp(to, "UTF-8") == 0 && strcmp(from, "ISO-8859-1") == 0) {
char_conv_latin1ToUtf8 = 1;
}
else if(strcmp(to,"ISO-8859-1")==0 && strcmp(from,"UTF-8")==0) {
} else if (strcmp(to, "ISO-8859-1") == 0 && strcmp(from, "UTF-8") == 0) {
char_conv_latin1ToUtf8 = -1;
}
if(char_conv_latin1ToUtf8!=0) {
if (char_conv_latin1ToUtf8 != 0) {
char_conv_to = strdup(to);
char_conv_from = strdup(from);
return 0;
}
#ifdef HAVE_ICONV
if((char_conv_iconv = iconv_open(to,from))==(iconv_t)(-1)) return -1;
if ((char_conv_iconv = iconv_open(to, from)) == (iconv_t) (-1))
return -1;
char_conv_to = strdup(to);
char_conv_from = strdup(from);
......@@ -83,37 +94,42 @@ int setCharSetConversion(char * to, char * from) {
return -1;
}
char * convStrDup(char * string) {
if(!char_conv_to) return NULL;
char *convStrDup(char *string)
{
if (!char_conv_to)
return NULL;
if(char_conv_same) return strdup(string);
if (char_conv_same)
return strdup(string);
#ifdef HAVE_ICONV
if(char_conv_use_iconv) {
if (char_conv_use_iconv) {
char buffer[BUFFER_SIZE];
size_t inleft = strlen(string);
char * ret;
char *ret;
size_t outleft;
size_t retlen = 0;
size_t err;
char * bufferPtr;
char *bufferPtr;
ret = malloc(1);
ret[0] = '\0';
while(inleft) {
while (inleft) {
bufferPtr = buffer;
outleft = BUFFER_SIZE;
err = iconv(char_conv_iconv,&string,&inleft,&bufferPtr,
&outleft);
if(outleft==BUFFER_SIZE || (err<0 && errno!=E2BIG)) {
err =
iconv(char_conv_iconv, &string, &inleft, &bufferPtr,
&outleft);
if (outleft == BUFFER_SIZE
|| (err < 0 && errno != E2BIG)) {
free(ret);
return NULL;
}
ret = realloc(ret,retlen+BUFFER_SIZE-outleft+1);
memcpy(ret+retlen,buffer,BUFFER_SIZE-outleft);
retlen+=BUFFER_SIZE-outleft;
ret = realloc(ret, retlen + BUFFER_SIZE - outleft + 1);
memcpy(ret + retlen, buffer, BUFFER_SIZE - outleft);
retlen += BUFFER_SIZE - outleft;
ret[retlen] = '\0';
}
......@@ -121,8 +137,8 @@ char * convStrDup(char * string) {
}
#endif
switch(char_conv_latin1ToUtf8) {
case 1:
switch (char_conv_latin1ToUtf8) {
case 1:
return latin1StrToUtf8Dup(string);
break;
case -1:
......@@ -133,10 +149,12 @@ char * convStrDup(char * string) {
return NULL;
}
void closeCharSetConversion() {
if(char_conv_to) {
static void closeCharSetConversion(void)
{
if (char_conv_to) {
#ifdef HAVE_ICONV
if(char_conv_use_iconv) iconv_close(char_conv_iconv);
if (char_conv_use_iconv)
iconv_close(char_conv_iconv);
#endif
free(char_conv_to);
free(char_conv_from);
......
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -21,10 +21,8 @@
#include "../config.h"
int setCharSetConversion(char * to, char * from);
int setCharSetConversion(char *to, char *from);
char * convStrDup(char * string);
void closeCharSetConversion();
char *convStrDup(char *string);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -25,39 +25,26 @@
#include "myfprintf.h"
#include "log.h"
#include "ack.h"
#include "sllist.h"
#include <unistd.h>
#include <stdio.h>
#define COMMAND_RETURN_KILL 10
#define COMMAND_RETURN_CLOSE 20
#define COMMAND_MASTER_READY 30
extern char * current_command;
extern int command_listNum;
int processListOfCommands(int fd, int *permission, int *expired,
int listOK, struct strnode *list);
int proccessListOfCommands(FILE * fp, int * permission, int * expired,
int listOK, List * list);
int processCommand(FILE * fp, unsigned int * permission, char * commandString);
int processCommand(int fd, int *permission, char *commandString);
void initCommands();
void finishCommands();
#define commandSuccess(fp) myfprintf(fp, "OK\n")
#define commandError(fp, error, format, ... ) \
{\
if(current_command) { \
myfprintf(fp, "ACK [%i@%i] {%s} " format "\n", \
(int)error, command_listNum, \
current_command, __VA_ARGS__); \
current_command = NULL; \
} \
else { \
myfprintf(stderr, "ACK [%i@%i] " format "\n", \
(int)error, command_listNum, \
__VA_ARGS__); \
} \
}
#define commandSuccess(fd) fdprintf(fd, "OK\n")
mpd_fprintf_ void commandError(int fd, int error, const char *fmt, ...);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* Compressor logic by
* (c)2003-6 fluffy@beesbuzz.biz
*
* 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 <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include "compress.h"
#ifdef USE_X
#include <X11/Xlib.h>
#include <X11/Xutil.h>
static Display *display;
static Window window;
static Visual *visual;
static int screen;
static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
#endif
static int *peaks = NULL;
static int gainCurrent, gainTarget;
static struct {
int show_mon;
int anticlip;
int target;
int gainmax;
int gainsmooth;
int buckets;
} prefs;
#ifdef USE_X
static int mon_init = 0;
#endif
void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
int gainsmooth, int buckets)
{
static int lastsize = 0;
prefs.show_mon = show_mon;
prefs.anticlip = anticlip;
prefs.target = target;
prefs.gainmax = gainmax;
prefs.gainsmooth = gainsmooth;
prefs.buckets = buckets;
/* Allocate the peak structure */
peaks = realloc(peaks, sizeof(int)*prefs.buckets);
if (prefs.buckets > lastsize)
memset(peaks + lastsize, 0, sizeof(int)*(prefs.buckets
- lastsize));
lastsize = prefs.buckets;
#ifdef USE_X
/* Configure the monitor window if needed */
if (show_mon && !mon_init)
{
display = XOpenDisplay(getenv("DISPLAY"));
/* We really shouldn't try to init X if there's no X */
if (!display)
{
fprintf(stderr,
"X not detected; disabling monitor window\n");
show_mon = prefs.show_mon = 0;
}
}
if (show_mon && !mon_init)
{
XGCValues gcv;
XColor col;
gainCurrent = gainTarget = (1 << GAINSHIFT);
screen = DefaultScreen(display);
visual = DefaultVisual(display, screen);
window = XCreateSimpleWindow(display,
RootWindow(display, screen),
0, 0, prefs.buckets, 128 + 8, 0,
BlackPixel(display, screen),
WhitePixel(display, screen));
XStoreName(display, window, "AudioCompress monitor");
gcv.foreground = BlackPixel(display, screen);
blackGC = XCreateGC(display, window, GCForeground, &gcv);
gcv.foreground = WhitePixel(display, screen);
whiteGC = XCreateGC(display, window, GCForeground, &gcv);
col.red = 0;
col.green = 0;
col.blue = 65535;
XAllocColor(display, DefaultColormap(display, screen), &col);
gcv.foreground = col.pixel;
blueGC = XCreateGC(display, window, GCForeground, &gcv);
col.red = 65535;
col.green = 65535;
col.blue = 0;
XAllocColor(display, DefaultColormap(display, screen), &col);
gcv.foreground = col.pixel;
yellowGC = XCreateGC(display, window, GCForeground, &gcv);
col.red = 32767;
col.green = 32767;
col.blue = 0;
XAllocColor(display, DefaultColormap(display, screen), &col);
gcv.foreground = col.pixel;
dkyellowGC = XCreateGC(display, window, GCForeground, &gcv);
col.red = 65535;
col.green = 0;
col.blue = 0;
XAllocColor(display, DefaultColormap(display, screen), &col);
gcv.foreground = col.pixel;
redGC = XCreateGC(display, window, GCForeground, &gcv);
mon_init = 1;
}
if (mon_init)
{
if (show_mon)
XMapWindow(display, window);
else
XUnmapWindow(display, window);
XResizeWindow(display, window, prefs.buckets, 128 + 8);
XFlush(display);
}
#endif
}
void CompressFree(void)
{
#ifdef USE_X
if (mon_init)
{
XFreeGC(display, blackGC);
XFreeGC(display, whiteGC);
XFreeGC(display, blueGC);
XFreeGC(display, yellowGC);
XFreeGC(display, dkyellowGC);
XFreeGC(display, redGC);
XDestroyWindow(display, window);
XCloseDisplay(display);
}
#endif
if (peaks)
free(peaks);
}
void CompressDo(void *data, unsigned int length)
{
int16_t *audio = (int16_t *)data, *ap;
int peak, pos;
int i;
int gr, gf, gn;
static int pn = -1;
#ifdef STATS
static int clip = 0;
#endif
static int clipped = 0;
if (!peaks)
return;
if (pn == -1)
{
for (i = 0; i < prefs.buckets; i++)
peaks[i] = 0;
}
pn = (pn + 1)%prefs.buckets;
#ifdef DEBUG
fprintf(stderr, "modifyNative16(0x%08x, %d)\n",(unsigned int)data,
length);
#endif
/* Determine peak's value and position */
peak = 1;
pos = 0;
#ifdef DEBUG
fprintf(stderr, "finding peak(b=%d)\n", pn);
#endif
ap = audio;
for (i = 0; i < length/2; i++)
{
int val = *ap;
if (val > peak)
{
peak = val;
pos = i;
} else if (-val > peak)
{
peak = -val;
pos = i;
}
ap++;
}
peaks[pn] = peak;
/* Only draw if needed, of course */
#ifdef USE_X
if (prefs.show_mon)
{
/* current amplitude */
XDrawLine(display, window, whiteGC,
pn, 0,
pn,
127 -
(peaks[pn]*gainCurrent >> (GAINSHIFT + 8)));
/* amplification */
XDrawLine(display, window, yellowGC,
pn,
127 - (peaks[pn]*gainCurrent
>> (GAINSHIFT + 8)),
pn, 127);
/* peak */
XDrawLine(display, window, blackGC,
pn, 127 - (peaks[pn] >> 8), pn, 127);
/* clip indicator */
if (clipped)
XDrawLine(display, window, redGC,
(pn + prefs.buckets - 1)%prefs.buckets,
126 - clipped/(length*512),
(pn + prefs.buckets - 1)%prefs.buckets,
127);
clipped = 0;
/* target line */
/* XDrawPoint(display, window, redGC, */
/* pn, 127 - TARGET/256); */
/* amplification edge */
XDrawLine(display, window, dkyellowGC,
pn,
127 - (peaks[pn]*gainCurrent
>> (GAINSHIFT + 8)),
pn - 1,
127 -
(peaks[(pn + prefs.buckets
- 1)%prefs.buckets]*gainCurrent
>> (GAINSHIFT + 8)));
}
#endif
for (i = 0; i < prefs.buckets; i++)
{
if (peaks[i] > peak)
{
peak = peaks[i];
pos = 0;
}
}
/* Determine target gain */
gn = (1 << GAINSHIFT)*prefs.target/peak;
if (gn <(1 << GAINSHIFT))
gn = 1 << GAINSHIFT;
gainTarget = (gainTarget *((1 << prefs.gainsmooth) - 1) + gn)
>> prefs.gainsmooth;
/* Give it an extra insignifigant nudge to counteract possible
** rounding error
*/
if (gn < gainTarget)
gainTarget--;
else if (gn > gainTarget)
gainTarget++;
if (gainTarget > prefs.gainmax << GAINSHIFT)
gainTarget = prefs.gainmax << GAINSHIFT;
#ifdef USE_X
if (prefs.show_mon)
{
int x;
/* peak*gain */
XDrawPoint(display, window, redGC,
pn,
127 - (peak*gainCurrent
>> (GAINSHIFT + 8)));
/* gain indicator */
XFillRectangle(display, window, whiteGC, 0, 128,
prefs.buckets, 8);
x = (gainTarget - (1 << GAINSHIFT))*prefs.buckets
/ ((prefs.gainmax - 1) << GAINSHIFT);
XDrawLine(display, window, redGC, x,
128, x, 128 + 8);
x = (gn - (1 << GAINSHIFT))*prefs.buckets
/ ((prefs.gainmax - 1) << GAINSHIFT);
XDrawLine(display, window, blackGC,
x, 132 - 1,
x, 132 + 1);
/* blue peak line */
XDrawLine(display, window, blueGC,
0, 127 - (peak >> 8), prefs.buckets,
127 - (peak >> 8));
XFlush(display);
XDrawLine(display, window, whiteGC,
0, 127 - (peak >> 8), prefs.buckets,
127 - (peak >> 8));
}
#endif
/* See if a peak is going to clip */
gn = (1 << GAINSHIFT)*32768/peak;
if (gn < gainTarget)
{
gainTarget = gn;
if (prefs.anticlip)
pos = 0;
} else
{
/* We're ramping up, so draw it out over the whole frame */
pos = length;
}
/* Determine gain rate necessary to make target */
if (!pos)
pos = 1;
gr = ((gainTarget - gainCurrent) << 16)/pos;
/* Do the shiznit */
gf = gainCurrent << 16;
#ifdef STATS
fprintf(stderr, "\rgain = %2.2f%+.2e ",
gainCurrent*1.0/(1 << GAINSHIFT),
(gainTarget - gainCurrent)*1.0/(1 << GAINSHIFT));
#endif
ap = audio;
for (i = 0; i < length/2; i++)
{
int sample;
/* Interpolate the gain */
gainCurrent = gf >> 16;
if (i < pos)
gf += gr;
else if (i == pos)
gf = gainTarget << 16;
/* Amplify */
sample = (*ap)*gainCurrent >> GAINSHIFT;
if (sample < -32768)
{
#ifdef STATS
clip++;
#endif
clipped += -32768 - sample;
sample = -32768;
} else if (sample > 32767)
{
#ifdef STATS
clip++;
#endif
clipped += sample - 32767;
sample = 32767;
}
*ap++ = sample;
}
#ifdef STATS
fprintf(stderr, "clip %d b%-3d ", clip, pn);
#endif
#ifdef DEBUG
fprintf(stderr, "\ndone\n");
#endif
}
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* interface to audio compression
* (c)2003-6 fluffy@beesbuzz.biz
*
* 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 COMPRESS_H
#define COMPRESS_H
/* These are copied from the AudioCompress config.h, mainly because CompressDo
* needs GAINSHIFT defined. The rest are here so they can be used as defaults
* to pass to CompressCfg(). -- jat */
#define ANTICLIP 0 /* Strict clipping protection */
#define TARGET 25000 /* Target level */
#define GAINMAX 32 /* The maximum amount to amplify by */
#define GAINSHIFT 10 /* How fine-grained the gain is */
#define GAINSMOOTH 8 /* How much inertia ramping has*/
#define BUCKETS 400 /* How long of a history to store */
void CompressCfg(int monitor,
int anticlip,
int target,
int maxgain,
int smooth,
int buckets);
void CompressDo(void *data, unsigned int numSamples);
void CompressFree(void);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -21,74 +21,75 @@
#include "../config.h"
#define CONF_PORT "port"
#define CONF_MUSIC_DIR "music_directory"
#define CONF_PLAYLIST_DIR "playlist_directory"
#define CONF_LOG_FILE "log_file"
#define CONF_ERROR_FILE "error_file"
#define CONF_CONN_TIMEOUT "connection_timeout"
#define CONF_MIXER_DEVICE "mixer_device"
#define CONF_MAX_CONN "max_connections"
#define CONF_MAX_PLAYLIST_LENGTH "max_playlist_length"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_MAX_COMMAND_LIST_SIZE "max_command_list_size"
#define CONF_MAX_OUTPUT_BUFFER_SIZE "max_output_buffer_size"
#define CONF_AUDIO_OUTPUT "audio_output"
#define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
#define CONF_BIND_TO_ADDRESS "bind_to_address"
#define CONF_MIXER_TYPE "mixer_type"
#define CONF_STATE_FILE "state_file"
#define CONF_USER "user"
#define CONF_DB_FILE "db_file"
#define CONF_LOG_LEVEL "log_level"
#define CONF_MIXER_CONTROL "mixer_control"
#define CONF_AUDIO_WRITE_SIZE "audio_write_size"
#define CONF_FS_CHARSET "filesystem_charset"
#define CONF_PASSWORD "password"
#define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_AUDIO_OUTPUT_FORMAT "audio_output_format"
#define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_HTTP_PROXY_HOST "http_proxy_host"
#define CONF_HTTP_PROXY_PORT "http_proxy_port"
#define CONF_HTTP_PROXY_USER "http_proxy_user"
#define CONF_HTTP_PROXY_PASSWORD "http_proxy_password"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
#define CONF_HTTP_PREBUFFER_SIZE "http_prebuffer_size"
#define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_PORT "port"
#define CONF_PID_FILE "pid_file"
#define CONF_MUSIC_DIR "music_directory"
#define CONF_PLAYLIST_DIR "playlist_directory"
#define CONF_LOG_FILE "log_file"
#define CONF_ERROR_FILE "error_file"
#define CONF_CONN_TIMEOUT "connection_timeout"
#define CONF_MIXER_DEVICE "mixer_device"
#define CONF_MAX_CONN "max_connections"
#define CONF_MAX_PLAYLIST_LENGTH "max_playlist_length"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_MAX_COMMAND_LIST_SIZE "max_command_list_size"
#define CONF_MAX_OUTPUT_BUFFER_SIZE "max_output_buffer_size"
#define CONF_AUDIO_OUTPUT "audio_output"
#define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
#define CONF_BIND_TO_ADDRESS "bind_to_address"
#define CONF_MIXER_TYPE "mixer_type"
#define CONF_STATE_FILE "state_file"
#define CONF_USER "user"
#define CONF_DB_FILE "db_file"
#define CONF_LOG_LEVEL "log_level"
#define CONF_MIXER_CONTROL "mixer_control"
#define CONF_FS_CHARSET "filesystem_charset"
#define CONF_PASSWORD "password"
#define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_AUDIO_OUTPUT_FORMAT "audio_output_format"
#define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_HTTP_PROXY_HOST "http_proxy_host"
#define CONF_HTTP_PROXY_PORT "http_proxy_port"
#define CONF_HTTP_PROXY_USER "http_proxy_user"
#define CONF_HTTP_PROXY_PASSWORD "http_proxy_password"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
#define CONF_HTTP_PREBUFFER_SIZE "http_prebuffer_size"
#define CONF_METADATA_TO_USE "metadata_to_use"
#define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_VOLUME_NORMALIZATION "volume_normalization"
typedef struct _BlockParam {
char * name;
char * value;
char *name;
char *value;
int line;
} BlockParam;
typedef struct _ConfigParam {
char * value;
char *value;
unsigned int line;
BlockParam * blockParams;
BlockParam *blockParams;
int numberOfBlockParams;
} ConfigParam;
void initConf();
void finishConf();
void readConf(char * file);
void readConf(char *file);
/* don't free the returned value
set _last_ to NULL to get first entry */
ConfigParam * getNextConfigParam(char * name, ConfigParam * last);
ConfigParam *getNextConfigParam(char *name, ConfigParam * last);
#define getConfigParam(name) getNextConfigParam(name, NULL)
char * getConfigParamValue(char * name);
char *getConfigParamValue(char *name);
char * forceAndGetConfigParamValue(char * name);
int getBoolConfigParam(char *name);
void registerConfigParam(char * name, int repeats, int block);
BlockParam *getBlockParam(ConfigParam * param, char *name);
BlockParam * getBlockParam(ConfigParam * param, char * name);
char * parseConfigFilePath(char * name, int force);
ConfigParam *parseConfigFilePath(char *name, int force);
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* 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 "dbUtils.h"
#include "directory.h"
#include "myfprintf.h"
#include "utils.h"
#include "playlist.h"
#include "tag.h"
#include "tagTracker.h"
#include "log.h"
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_FILE_KEY "filename"
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
#define LOCATE_TAG_ANY_KEY "any"
typedef struct _ListCommandItem {
mpd_sint8 tagType;
int numConditionals;
LocateTagItem *conditionals;
} ListCommandItem;
typedef struct _LocateTagItemArray {
int numItems;
LocateTagItem *items;
} LocateTagItemArray;
int getLocateTagItemType(char *str)
{
int i;
if (0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) {
return LOCATE_TAG_FILE_TYPE;
}
if (0 == strcasecmp(str, LOCATE_TAG_ANY_KEY)) {
return LOCATE_TAG_ANY_TYPE;
}
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if (0 == strcasecmp(str, mpdTagItemKeys[i]))
return i;
}
return -1;
}
static int initLocateTagItem(LocateTagItem * item, char *typeStr, char *needle)
{
item->tagType = getLocateTagItemType(typeStr);
if (item->tagType < 0)
return -1;
item->needle = strdup(needle);
return 0;
}
LocateTagItem *newLocateTagItem(char *typeStr, char *needle)
{
LocateTagItem *ret = malloc(sizeof(LocateTagItem));
if (initLocateTagItem(ret, typeStr, needle) < 0) {
free(ret);
ret = NULL;
}
return ret;
}
void freeLocateTagItemArray(int count, LocateTagItem * array)
{
int i;
for (i = 0; i < count; i++)
free(array[i].needle);
free(array);
}
int newLocateTagItemArrayFromArgArray(char *argArray[],
int numArgs, LocateTagItem ** arrayRet)
{
int i, j;
LocateTagItem *item;
if (numArgs == 0)
return 0;
if (numArgs % 2 != 0)
return -1;
*arrayRet = malloc(sizeof(LocateTagItem) * numArgs / 2);
for (i = 0, item = *arrayRet; i < numArgs / 2; i++, item++) {
if (initLocateTagItem
(item, argArray[i * 2], argArray[i * 2 + 1]) < 0)
goto fail;
}
return numArgs / 2;
fail:
for (j = 0; j < i; j++) {
free((*arrayRet)[j].needle);
}
free(*arrayRet);
*arrayRet = NULL;
return -1;
}
void freeLocateTagItem(LocateTagItem * item)
{
free(item->needle);
free(item);
}
static int countSongsInDirectory(int fd, Directory * directory, void *data)
{
int *count = (int *)data;
*count += directory->songs->numberOfNodes;
return 0;
}
static int printDirectoryInDirectory(int fd, Directory * directory,
void *data)
{
if (directory->path) {
fdprintf(fd, "directory: %s\n", getDirectoryPath(directory));
}
return 0;
}
static int printSongInDirectory(int fd, Song * song, void *data)
{
printSongUrl(fd, song);
return 0;
}
static int strstrSearchTag(Song * song, int type, char *str)
{
int i;
char *dup;
int ret = 0;
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
dup = strDupToUpper(getSongUrl(song));
if (strstr(dup, str))
ret = 1;
free(dup);
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
return ret;
}
}
if (!song->tag)
return 0;
for (i = 0; i < song->tag->numOfItems && !ret; i++) {
if (type != LOCATE_TAG_ANY_TYPE &&
song->tag->items[i].type != type) {
continue;
}
dup = strDupToUpper(song->tag->items[i].value);
if (strstr(dup, str))
ret = 1;
free(dup);
}
return ret;
}
static int searchInDirectory(int fd, Song * song, void *data)
{
LocateTagItemArray *array = data;
int i;
for (i = 0; i < array->numItems; i++) {
if (!strstrSearchTag(song, array->items[i].tagType,
array->items[i].needle)) {
return 0;
}
}
printSongInfo(fd, song);
return 0;
}
int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
{
int ret = -1;
int i;
char **originalNeedles = malloc(numItems * sizeof(char *));
LocateTagItemArray array;
for (i = 0; i < numItems; i++) {
originalNeedles[i] = items[i].needle;
items[i].needle = strDupToUpper(originalNeedles[i]);
}
array.numItems = numItems;
array.items = items;
ret = traverseAllIn(fd, name, searchInDirectory, NULL, &array);
for (i = 0; i < numItems; i++) {
free(items[i].needle);
items[i].needle = originalNeedles[i];
}
free(originalNeedles);
return ret;
}
static int tagItemFoundAndMatches(Song * song, int type, char *str)
{
int i;
if (type == LOCATE_TAG_FILE_TYPE) {
if (0 == strcmp(str, getSongUrl(song)))
return 1;
}
if (!song->tag)
return 0;
for (i = 0; i < song->tag->numOfItems; i++) {
if (song->tag->items[i].type != type)
continue;
if (0 == strcmp(str, song->tag->items[i].value))
return 1;
}
return 0;
}
static int findInDirectory(int fd, Song * song, void *data)
{
LocateTagItemArray *array = data;
int i;
for (i = 0; i < array->numItems; i++) {
if (!tagItemFoundAndMatches(song, array->items[i].tagType,
array->items[i].needle)) {
return 0;
}
}
printSongInfo(fd, song);
return 0;
}
int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
{
LocateTagItemArray array;
array.numItems = numItems;
array.items = items;
return traverseAllIn(fd, name, findInDirectory, NULL, (void *)&array);
}
int printAllIn(int fd, char *name)
{
return traverseAllIn(fd, name, printSongInDirectory,
printDirectoryInDirectory, NULL);
}
static int directoryAddSongToPlaylist(int fd, Song * song, void *data)
{
return addSongToPlaylist(fd, song, 0);
}
int addAllIn(int fd, char *name)
{
return traverseAllIn(fd, name, directoryAddSongToPlaylist, NULL, NULL);
}
static int directoryPrintSongInfo(int fd, Song * song, void *data)
{
return printSongInfo(fd, song);
}
static int sumSongTime(int fd, Song * song, void *data)
{
unsigned long *time = (unsigned long *)data;
if (song->tag && song->tag->time >= 0)
*time += song->tag->time;
return 0;
}
int printInfoForAllIn(int fd, char *name)
{
return traverseAllIn(fd, name, directoryPrintSongInfo,
printDirectoryInDirectory, NULL);
}
int countSongsIn(int fd, char *name)
{
int count = 0;
void *ptr = (void *)&count;
traverseAllIn(fd, name, NULL, countSongsInDirectory, ptr);
return count;
}
unsigned long sumSongTimesIn(int fd, char *name)
{
unsigned long dbPlayTime = 0;
void *ptr = (void *)&dbPlayTime;
traverseAllIn(fd, name, sumSongTime, NULL, ptr);
return dbPlayTime;
}
static ListCommandItem *newListCommandItem(int tagType, int numConditionals,
LocateTagItem * conditionals)
{
ListCommandItem *item = malloc(sizeof(ListCommandItem));
item->tagType = tagType;
item->numConditionals = numConditionals;
item->conditionals = conditionals;
return item;
}
static void freeListCommandItem(ListCommandItem * item)
{
free(item);
}
static void visitTag(int fd, Song * song, int tagType)
{
int i;
MpdTag *tag = song->tag;
if (tagType == LOCATE_TAG_FILE_TYPE) {
printSongUrl(fd, song);
return;
}
if (!tag)
return;
for (i = 0; i < tag->numOfItems; i++) {
if (tag->items[i].type == tagType) {
visitInTagTracker(tagType, tag->items[i].value);
}
}
}
static int listUniqueTagsInDirectory(int fd, Song * song, void *data)
{
ListCommandItem *item = data;
int i;
for (i = 0; i < item->numConditionals; i++) {
if (!tagItemFoundAndMatches(song, item->conditionals[i].tagType,
item->conditionals[i].needle)) {
return 0;
}
}
visitTag(fd, song, item->tagType);
return 0;
}
int listAllUniqueTags(int fd, int type, int numConditionals,
LocateTagItem * conditionals)
{
int ret;
ListCommandItem *item = newListCommandItem(type, numConditionals,
conditionals);
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
resetVisitedFlagsInTagTracker(type);
}
ret = traverseAllIn(fd, NULL, listUniqueTagsInDirectory, NULL,
(void *)item);
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
printVisitedInTagTracker(fd, type);
}
freeListCommandItem(item);
return ret;
}
static int sumSavedFilenameMemoryInDirectory(int fd, Directory * dir,
void *data)
{
int *sum = data;
if (!dir->path)
return 0;
*sum += (strlen(getDirectoryPath(dir)) + 1 - sizeof(Directory *)) *
dir->songs->numberOfNodes;
return 0;
}
static int sumSavedFilenameMemoryInSong(int fd, Song * song, void *data)
{
int *sum = data;
*sum += strlen(song->url) + 1;
return 0;
}
void printSavedMemoryFromFilenames(void)
{
int sum = 0;
traverseAllIn(STDERR_FILENO, NULL, sumSavedFilenameMemoryInSong,
sumSavedFilenameMemoryInDirectory, (void *)&sum);
DEBUG("saved memory from filenames: %i\n", sum);
}
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* 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 DB_UTILS_H
#define DB_UTILS_H
#include <stdio.h>
#include "tag.h"
/* struct used for search, find, list queries */
typedef struct _LocateTagItem {
mpd_sint8 tagType;
/* what we are looking for */
char *needle;
} LocateTagItem;
int getLocateTagItemType(char *str);
/* returns NULL if not a known type */
LocateTagItem *newLocateTagItem(char *typeString, char *needle);
/* return number of items or -1 on error */
int newLocateTagItemArrayFromArgArray(char *argArray[], int numArgs,
LocateTagItem ** arrayRet);
void freeLocateTagItemArray(int count, LocateTagItem * array);
void freeLocateTagItem(LocateTagItem * item);
int printAllIn(int fd, char *name);
int addAllIn(int fd, char *name);
int printInfoForAllIn(int fd, char *name);
int searchForSongsIn(int fd, char *name, int numItems,
LocateTagItem * items);
int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items);
int countSongsIn(int fd, char *name);
unsigned long sumSongTimesIn(int fd, char *name);
int listAllUniqueTags(int fd, int type, int numConditiionals,
LocateTagItem * conditionals);
void printSavedMemoryFromFilenames();
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -27,6 +27,7 @@
#include <stdio.h>
#include <sys/param.h>
#include <signal.h>
#define DECODE_TYPE_FILE 0
#define DECODE_TYPE_URL 1
......@@ -56,12 +57,12 @@ typedef struct _DecoderControl {
volatile mpd_sint8 seekable;
volatile mpd_sint8 cycleLogFiles;
volatile double seekWhere;
AudioFormat audioFormat;
char utf8url[MAXPATHLEN+1];
volatile float totalTime;
AudioFormat audioFormat;
char utf8url[MAXPATHLEN + 1];
volatile float totalTime;
} DecoderControl;
void decodeSigHandler(int sig);
void decodeSigHandler(int sig, siginfo_t * siginfo, void *v);
void decode();
......
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -24,26 +24,36 @@
#include "song.h"
#include "list.h"
#include <stdio.h>
#include <sys/param.h>
typedef List DirectoryList;
extern char * directory_db;
typedef struct _DirectoryStat {
ino_t inode;
dev_t device;
} DirectoryStat;
void readDirectoryDBIfUpdateIsFinished();
typedef struct _Directory {
char *path;
DirectoryList *subDirectories;
SongList *songs;
struct _Directory *parent;
DirectoryStat *stat;
} Directory;
void clearUpdatePid();
void readDirectoryDBIfUpdateIsFinished();
int isUpdatingDB();
void directory_sigChldHandler(int pid, int status);
int updateInit(FILE * fp, List * pathList);
int updateInit(int fd, List * pathList);
void initMp3Directory();
void closeMp3Directory();
int printDirectoryInfo(FILE * fp, char * dirname);
int printDirectoryInfo(int fd, char *dirname);
int checkDirectoryDB();
int writeDirectoryDB();
......@@ -51,22 +61,14 @@ int readDirectoryDB();
void updateMp3Directory();
int printAllIn(FILE * fp, char * name);
int addAllIn(FILE * fp, char * name);
int printInfoForAllIn(FILE * fp, char * name);
Song *getSongFromDB(char *file);
int searchForSongsIn(FILE * fp, char * name, char * item, char * string);
int findSongsIn(FILE * fp, char * name, char * item, char * string);
int countSongsIn(FILE * fp, char * name);
unsigned long sumSongTimesIn(FILE * fp, char * name);
time_t getDbModTime();
Song * getSongFromDB(char * file);
int traverseAllIn(int fd, char *name,
int (*forEachSong) (int, Song *, void *),
int (*forEachDir) (int, Directory *, void *), void *data);
time_t getDbModTime();
#define getDirectoryPath(dir) ((dir && dir->path) ? dir->path : "")
#endif
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* 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 MPD_GCC_H
#define MPD_GCC_H
/* this allows us to take advantage of special gcc features while still
* allowing other compilers to compile:
*
* example taken from: http://rlove.org/log/2005102601
*/
/* disabled (0) until I fix all the warnings :) */
#if __GNUC__ >= 3
# define mpd_const __attribute__ ((const))
# define mpd_deprecated __attribute__ ((deprecated))
# define mpd_malloc __attribute__ ((malloc))
# define mpd_must_check __attribute__ ((warn_unused_result))
# define mpd_noreturn __attribute__ ((noreturn))
# define mpd_packed __attribute__ ((packed))
/* these are very useful for type checking */
# define mpd_printf __attribute__ ((format(printf,1,2)))
# define mpd_fprintf __attribute__ ((format(printf,2,3)))
# define mpd_fprintf_ __attribute__ ((format(printf,3,4)))
# define mpd_pure __attribute__ ((pure))
# define mpd_scanf __attribute__ ((format(scanf,1,2)))
# define mpd_unused __attribute__ ((unused))
# define mpd_used __attribute__ ((used))
/* # define inline inline __attribute__ ((always_inline)) */
# define mpd_noinline __attribute__ ((noinline))
# define mpd_likely(x) __builtin_expect (!!(x), 1)
# define mpd_unlikely(x) __builtin_expect (!!(x), 0)
#else
# define mpd_const
# define mpd_deprecated
# define mpd_malloc
# define mpd_must_check
# define mpd_noreturn
# define mpd_packed
# define mpd_printf
# define mpd_fprintf
# define mpd_fprintf_
# define mpd_pure
# define mpd_scanf
# define mpd_unused
# define mpd_used
/* # define inline */
# define mpd_noinline
# define mpd_likely(x) (x)
# define mpd_unlikely(x) (x)
#endif
#endif /* MPD_GCC_H */
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -24,40 +24,60 @@
#include <stdlib.h>
#include <string.h>
static List * inputPlugin_list = NULL;
static List *inputPlugin_list = NULL;
void loadInputPlugin(InputPlugin * inputPlugin) {
if(!inputPlugin) return;
if(!inputPlugin->name) return;
void loadInputPlugin(InputPlugin * inputPlugin)
{
if (!inputPlugin)
return;
if (!inputPlugin->name)
return;
if(inputPlugin->initFunc && inputPlugin->initFunc() < 0) return;
if (inputPlugin->initFunc && inputPlugin->initFunc() < 0)
return;
insertInList(inputPlugin_list, inputPlugin->name, (void *)inputPlugin);
}
void unloadInputPlugin(InputPlugin * inputPlugin) {
if(inputPlugin->finishFunc) inputPlugin->finishFunc();
void unloadInputPlugin(InputPlugin * inputPlugin)
{
if (inputPlugin->finishFunc)
inputPlugin->finishFunc();
deleteFromList(inputPlugin_list, inputPlugin->name);
}
static int stringFoundInStringArray(char ** array, char * suffix) {
while(array && *array) {
if(strcasecmp(*array, suffix) == 0) return 1;
static int stringFoundInStringArray(char **array, char *suffix)
{
while (array && *array) {
if (strcasecmp(*array, suffix) == 0)
return 1;
array++;
}
return 0;
}
InputPlugin * getInputPluginFromSuffix(char * suffix) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin = NULL;
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
{
static ListNode *pos = NULL;
ListNode *node;
InputPlugin *plugin;
if (suffix == NULL)
return NULL;
if(suffix == NULL) return NULL;
if (next) {
if (pos)
node = pos;
else
return NULL;
} else
node = inputPlugin_list->firstNode;
while(node != NULL) {
while (node != NULL) {
plugin = node->data;
if(stringFoundInStringArray(plugin->suffixes, suffix)) {
if (stringFoundInStringArray(plugin->suffixes, suffix)) {
pos = node->nextNode;
return plugin;
}
node = node->nextNode;
......@@ -66,15 +86,21 @@ InputPlugin * getInputPluginFromSuffix(char * suffix) {
return NULL;
}
InputPlugin * getInputPluginFromMimeType(char * mimeType) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin = NULL;
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next)
{
static ListNode *pos = NULL;
ListNode *node;
InputPlugin *plugin;
if (mimeType == NULL)
return NULL;
if(mimeType == NULL) return NULL;
node = (next && pos) ? pos : inputPlugin_list->firstNode;
while(node != NULL) {
while (node != NULL) {
plugin = node->data;
if(stringFoundInStringArray(plugin->mimeTypes, mimeType)) {
if (stringFoundInStringArray(plugin->mimeTypes, mimeType)) {
pos = node->nextNode;
return plugin;
}
node = node->nextNode;
......@@ -83,51 +109,60 @@ InputPlugin * getInputPluginFromMimeType(char * mimeType) {
return NULL;
}
InputPlugin * getInputPluginFromName(char * name) {
void * plugin = NULL;
InputPlugin *getInputPluginFromName(char *name)
{
void *plugin = NULL;
findInList(inputPlugin_list, name, &plugin);
return (InputPlugin *)plugin;
return (InputPlugin *) plugin;
}
void printAllInputPluginSuffixes(FILE * fp) {
ListNode * node = inputPlugin_list->firstNode;
InputPlugin * plugin;
char ** suffixes;
void printAllInputPluginSuffixes(FILE * fp)
{
ListNode *node = inputPlugin_list->firstNode;
InputPlugin *plugin;
char **suffixes;
while(node) {
plugin = (InputPlugin *)node->data;
while (node) {
plugin = (InputPlugin *) node->data;
suffixes = plugin->suffixes;
while(suffixes && *suffixes) {
myfprintf(fp, "%s ", *suffixes);
while (suffixes && *suffixes) {
fprintf(fp, "%s ", *suffixes);
suffixes++;
}
node = node->nextNode;
}
myfprintf(fp, "\n");
fprintf(fp, "\n");
fflush(fp);
}
extern InputPlugin mp3Plugin;
extern InputPlugin oggPlugin;
extern InputPlugin oggvorbisPlugin;
extern InputPlugin flacPlugin;
extern InputPlugin oggflacPlugin;
extern InputPlugin audiofilePlugin;
extern InputPlugin mp4Plugin;
extern InputPlugin mpcPlugin;
extern InputPlugin aacPlugin;
extern InputPlugin modPlugin;
void initInputPlugins() {
inputPlugin_list = makeList(NULL);
void initInputPlugins(void)
{
inputPlugin_list = makeList(NULL, 1);
/* load plugins here */
loadInputPlugin(&mp3Plugin);
loadInputPlugin(&oggPlugin);
loadInputPlugin(&oggvorbisPlugin);
loadInputPlugin(&oggflacPlugin);
loadInputPlugin(&flacPlugin);
loadInputPlugin(&audiofilePlugin);
loadInputPlugin(&mp4Plugin);
loadInputPlugin(&mpcPlugin);
loadInputPlugin(&modPlugin);
}
void finishInputPlugins() {
void finishInputPlugins(void)
{
freeList(inputPlugin_list);
}
/* the Music Player Daemon (MPD)
* (c)2003-2004 by Warren Dukes (shank@mercury.chem.pitt.edu)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
......@@ -25,32 +25,55 @@
#include "outputBuffer.h"
#include "tag.h"
/* valid values for streamTypes in the InputPlugin struct: */
#define INPUT_PLUGIN_STREAM_FILE 0x01
#define INPUT_PLUGIN_STREAM_URL 0x02
typedef int (* InputPlugin_initFunc) ();
/* optional, set this to NULL if the InputPlugin doesn't have/need one
* this must return < 0 if there is an error and >= 0 otherwise */
typedef int (*InputPlugin_initFunc) ();
typedef void (* InputPlugin_finishFunc) ();
/* optional, set this to NULL if the InputPlugin doesn't have/need one */
typedef void (*InputPlugin_finishFunc) ();
typedef int (* InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
InputStream *);
/* boolean return value, returns 1 if the InputStream is decodable by
* the InputPlugin, 0 if not */
typedef unsigned int (*InputPlugin_tryDecodeFunc) (InputStream *);
typedef int (* InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
char * path);
/* this will be used to decode InputStreams, and is recommended for files
* and networked (HTTP) connections.
*
* returns -1 on error, 0 on success */
typedef int (*InputPlugin_streamDecodeFunc) (OutputBuffer *, DecoderControl *,
InputStream *);
/* use this if and only if your InputPlugin can only be passed a filename or
* handle as input, and will not allow callbacks to be set (like Ogg-Vorbis
* and FLAC libraries allow)
*
* returns -1 on error, 0 on success */
typedef int (*InputPlugin_fileDecodeFunc) (OutputBuffer *, DecoderControl *,
char *path);
/* file should be the full path! */
typedef MpdTag * (* InputPlugin_tagDupFunc) (char * file);
/* file should be the full path! Returns NULL if a tag cannot be found
* or read */
typedef MpdTag *(*InputPlugin_tagDupFunc) (char *file);
typedef struct _InputPlugin {
char * name;
char *name;
InputPlugin_initFunc initFunc;
InputPlugin_finishFunc finishFunc;
InputPlugin_tryDecodeFunc tryDecodeFunc;
InputPlugin_streamDecodeFunc streamDecodeFunc;
InputPlugin_fileDecodeFunc fileDecodeFunc;
InputPlugin_tagDupFunc tagDupFunc;
/* one or more of the INPUT_PLUGIN_STREAM_* values OR'd together */
unsigned char streamTypes;
char ** suffixes;
char ** mimeTypes;
/* last element in these arrays must always be a NULL: */
char **suffixes;
char **mimeTypes;
} InputPlugin;
/* individual functions to load/unload plugins */
......@@ -59,11 +82,11 @@ void unloadInputPlugin(InputPlugin * inputPlugin);
/* interface for using plugins */
InputPlugin * getInputPluginFromSuffix(char * suffix);
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next);
InputPlugin * getInputPluginFromMimeType(char * mimeType);
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next);
InputPlugin * getInputPluginFromName(char * name);
InputPlugin *getInputPluginFromName(char *name);
void printAllInputPluginSuffixes(FILE * fp);
......
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* Common data structures and functions used by FLAC and OggFLAC
* (c) 2005 by Eric Wong <normalperson@yhbt.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../inputPlugin.h"
#if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC)
#include "_flac_common.h"
#include "../log.h"
#include "../tag.h"
#include "../inputStream.h"
#include "../outputBuffer.h"
#include "../decode.h"
#include "../replayGain.h"
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <FLAC/format.h>
#include <FLAC/metadata.h>
void init_FlacData(FlacData * data, OutputBuffer * cb,
DecoderControl * dc, InputStream * inStream)
{
data->chunk_length = 0;
data->time = 0;
data->position = 0;
data->bitRate = 0;
data->cb = cb;
data->dc = dc;
data->inStream = inStream;
data->replayGainInfo = NULL;
data->tag = NULL;
}
static int flacFindVorbisCommentFloat(const FLAC__StreamMetadata * block,
char *cmnt, float *fl)
{
int offset =
FLAC__metadata_object_vorbiscomment_find_entry_from(block, 0, cmnt);
if (offset >= 0) {
size_t pos = strlen(cmnt) + 1; /* 1 is for '=' */
int len = block->data.vorbis_comment.comments[offset].length
- pos;
if (len > 0) {
unsigned char tmp;
unsigned char *dup = &(block->data.vorbis_comment.
comments[offset].entry[pos]);
tmp = dup[len];
dup[len] = '\0';
*fl = atof((char *)dup);
dup[len] = tmp;
return 1;
}
}
return 0;
}
/* replaygain stuff by AliasMrJones */
static void flacParseReplayGain(const FLAC__StreamMetadata * block,
FlacData * data)
{
unsigned int found = 0;
if (data->replayGainInfo)
freeReplayGainInfo(data->replayGainInfo);
data->replayGainInfo = newReplayGainInfo();
found &= flacFindVorbisCommentFloat(block, "replaygain_album_gain",
&data->replayGainInfo->albumGain);
found &= flacFindVorbisCommentFloat(block, "replaygain_album_peak",
&data->replayGainInfo->albumPeak);
found &= flacFindVorbisCommentFloat(block, "replaygain_track_gain",
&data->replayGainInfo->trackGain);
found &= flacFindVorbisCommentFloat(block, "replaygain_track_peak",
&data->replayGainInfo->trackPeak);
if (!found) {
freeReplayGainInfo(data->replayGainInfo);
data->replayGainInfo = NULL;
}
}
/* tracknumber is used in VCs, MPD uses "track" ..., all the other
* tag names match */
static const char *VORBIS_COMMENT_TRACK_KEY = "tracknumber";
static const char *VORBIS_COMMENT_DISC_KEY = "discnumber";
static unsigned int commentMatchesAddToTag(const
FLAC__StreamMetadata_VorbisComment_Entry
* entry, unsigned int itemType,
MpdTag ** tag)
{
const char *str;
size_t slen;
int vlen;
switch (itemType) {
case TAG_ITEM_TRACK:
str = VORBIS_COMMENT_TRACK_KEY;
break;
case TAG_ITEM_DISC:
str = VORBIS_COMMENT_DISC_KEY;
break;
default:
str = mpdTagItemKeys[itemType];
}
slen = strlen(str);
vlen = entry->length - slen - 1;
if ((vlen > 0) && (0 == strncasecmp(str, (char *)entry->entry, slen))
&& (*(entry->entry + slen) == '=')) {
if (!*tag)
*tag = newMpdTag();
addItemToMpdTagWithLen(*tag, itemType,
(char *)(entry->entry + slen + 1), vlen);
return 1;
}
return 0;
}
MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
MpdTag * tag)
{
unsigned int i, j;
FLAC__StreamMetadata_VorbisComment_Entry *comments;
comments = block->data.vorbis_comment.comments;
for (i = block->data.vorbis_comment.num_comments; i != 0; --i) {
for (j = TAG_NUM_OF_ITEM_TYPES; j--;) {
if (commentMatchesAddToTag(comments, j, &tag))
break;
}
comments++;
}
return tag;
}
void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
FlacData * data)
{
DecoderControl *dc = data->dc;
const FLAC__StreamMetadata_StreamInfo *si = &(block->data.stream_info);
switch (block->type) {
case FLAC__METADATA_TYPE_STREAMINFO:
dc->audioFormat.bits = si->bits_per_sample;
dc->audioFormat.sampleRate = si->sample_rate;
dc->audioFormat.channels = si->channels;
dc->totalTime = ((float)si->total_samples) / (si->sample_rate);
getOutputAudioFormat(&(dc->audioFormat),
&(data->cb->audioFormat));
break;
case FLAC__METADATA_TYPE_VORBIS_COMMENT:
flacParseReplayGain(block, data);
default:
break;
}
}
void flac_error_common_cb(const char *plugin,
const FLAC__StreamDecoderErrorStatus status,
FlacData * data)
{
if (data->dc->stop)
return;
switch (status) {
case FLAC__STREAM_DECODER_ERROR_STATUS_LOST_SYNC:
ERROR("%s lost sync\n", plugin);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_BAD_HEADER:
ERROR("bad %s header\n", plugin);
break;
case FLAC__STREAM_DECODER_ERROR_STATUS_FRAME_CRC_MISMATCH:
ERROR("%s crc mismatch\n", plugin);
break;
default:
ERROR("unknown %s error\n", plugin);
}
}
#endif /* HAVE_FLAC || HAVE_OGGFLAC */
/* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org
*
* Common data structures and functions used by FLAC and OggFLAC
* (c) 2005 by Eric Wong <normalperson@yhbt.net>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#ifndef _FLAC_COMMON_H
#define _FLAC_COMMON_H
#include "../inputPlugin.h"
#if defined(HAVE_FLAC) || defined(HAVE_OGGFLAC)
#include "../tag.h"
#include "../inputStream.h"
#include "../outputBuffer.h"
#include "../decode.h"
#include <FLAC/seekable_stream_decoder.h>
#include <FLAC/metadata.h>
#define FLAC_CHUNK_SIZE 4080
typedef struct {
unsigned char chunk[FLAC_CHUNK_SIZE];
int chunk_length;
float time;
int bitRate;
FLAC__uint64 position;
OutputBuffer *cb;
DecoderControl *dc;
InputStream *inStream;
ReplayGainInfo *replayGainInfo;
MpdTag *tag;
} FlacData;
/* initializes a given FlacData struct */
void init_FlacData(FlacData * data, OutputBuffer * cb,
DecoderControl * dc, InputStream * inStream);
void flac_metadata_common_cb(const FLAC__StreamMetadata * block,
FlacData * data);
void flac_error_common_cb(const char *plugin,
FLAC__StreamDecoderErrorStatus status,
FlacData * data);
MpdTag *copyVorbisCommentBlockToMpdTag(const FLAC__StreamMetadata * block,
MpdTag * tag);
/* keep this inlined, this is just macro but prettier :) */
static inline int flacSendChunk(FlacData * data)
{
if (sendDataToOutputBuffer(data->cb, NULL, data->dc, 1, data->chunk,
data->chunk_length, data->time,
data->bitRate,
data->replayGainInfo) ==
OUTPUT_BUFFER_DC_STOP)
return -1;
return 0;
}
#endif /* HAVE_FLAC || HAVE_OGGFLAC */
#endif /* _FLAC_COMMON_H */
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.
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.
This source diff could not be displayed because it is too large. You can view the blob instead.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
This diff is collapsed. Click to expand it.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment