Commit 1370cca9 authored by Led's avatar Led

0.13.0

parent ffeacd4b
Developer -> Warren Dukes <warren.dukes@gmail.com> Current Developers
Developer -> tw-nym ------------------
audiofile support and command.c cleanup -> normalperson Warren Dukes <warren.dukes@gmail.com>
setuid patch -> Nagilum general
'next' and 'previous' patch -> Niklas Hofer
command.c and signal handling cleanup -> mackstann J. Alexander Treuman <jat@spatialrift.net>
replayGain -> AliasMrJones general, MP3, ID3, PulseAudio, format conversion, stored playlists
Eric Wong <normalperson@yhbt.net>
general, FLAC, mpd-ke branch
Jos Anarch <anarchsss@gmail.com>
JACK plugin
Guus Sliepen <guus@sliepen.eu.org>
libsamplerate code
Jim Ramsay <i.am@jimramsay.com>
Zerconf/avahi support
Qball Cow <qballcow@gmail.com>
Playlist commands
Patrik Weiskircher <pat@icore.at>
Stored playlist commands
Former Developers
-----------------
tw-nym
Nagilum
setuid
Niklas Hofer
'next' and 'previous' patch
mackstann
command.c and signal handling cleanup
AliasMrJones
replayGain
mp4ff copyrighted by M. Bakker, Ahead Software AG, http://www.nero.com mp4ff copyrighted by M. Bakker, Ahead Software AG, http://www.nero.com
compress.[ch] copyrighted by fluffy <fluffy@beesbuzz.biz> compress.[ch] copyrighted by fluffy <fluffy@beesbuzz.biz>
ver 0.13.0 (2007/5/28)
* New JACK audio output
* Support for "file" as an alternative to "filename" in search, find, and list
* FLAC 1.1.3 API support
* New playlistadd command for adding to stored playlists
* New playlistclear command for clearing stored playlists
* Fix a bug where "find any" and "list <type> any" wouldn't return any results
* Make "list any" return an error instead of no results and an OK
* New gapless_mp3_playback option to disable gapless MP3 playback
* Support for seeking HTTP streams
* Zeroconf support using Avahi
* libsamplerate support for high quality audio resampling
* ID3v2 "Original Artist/Performer" tag support
* New playlistsearch command for searching the playlist (similar to "search")
* New playlistfind command for finding songs in the playlist (similar to "find")
* libmikmod 3.2.0 beta support
* New tagtypes command for retrieving a list of available tag types
* Fix a bug where no ACK was returned if loading a playlist failed
* Fix a bug where db_update in stats would be 0 after initial database creation
* New count command for getting stats on found songs (similar to "find")
* New playlistmove command for moving songs in stored playlists
* New playlistdelete command for deleting songs from stored playlists
* New rename command for renaming stored playlists
* Increased default buffer_before_play from 0% to 10% to prevent skipping
* Lots of bug fixes, cleaned up code, and performance improvements
ver 0.12.2 (2007/3/20) ver 0.12.2 (2007/3/20)
* Fix a bug where clients could cause MPD to segfault * Fix a bug where clients could cause MPD to segfault
...@@ -15,7 +41,6 @@ ver 0.12.0 (2006/9/22) ...@@ -15,7 +41,6 @@ ver 0.12.0 (2006/9/22)
* ALSA * ALSA
* OSS * OSS
* OS X * OS X
* Sun
* Media MVP * Media MVP
* PulseAudio * PulseAudio
* Shout (Icecast or Shoutcast) * Shout (Icecast or Shoutcast)
......
...@@ -20,6 +20,9 @@ Linux. You will need libasound. ...@@ -20,6 +20,9 @@ Linux. You will need libasound.
PulseAudio - http://www.pulseaudio.org/ PulseAudio - http://www.pulseaudio.org/
An advanced sound daemon. You will need libpulse. An advanced sound daemon. You will need libpulse.
JACK - http://www.jackaudio.org/
A low-latency sound daemon.
libshout - http://www.icecast.org/ libshout - http://www.icecast.org/
For streaming to an Icecast or Shoutcast server. For streaming to an Icecast or Shoutcast server.
...@@ -43,7 +46,8 @@ For FLAC support. You will need version 1.1.0 or higher of libflac. ...@@ -43,7 +46,8 @@ For FLAC support. You will need version 1.1.0 or higher of libflac.
OggFLAC - http://www.xiph.org/ogg/vorbis/ and http://flac.sourceforge.net/ OggFLAC - http://www.xiph.org/ogg/vorbis/ and http://flac.sourceforge.net/
For OggFLAC support. You will need liboggflac, which can be built from the For OggFLAC support. You will need liboggflac, which can be built from the
FLAC sources if libogg is already installed. FLAC sources if libogg is already installed. Versions of flac 1.1.3 and
greater will automatically detect and use OggFLAC if it's available.
Audio File - http://www.68k.org/~michael/audiofile/ Audio File - http://www.68k.org/~michael/audiofile/
For WAVE, AIFF, and AU support. You will need libaudiofile. For WAVE, AIFF, and AU support. You will need libaudiofile.
...@@ -57,6 +61,15 @@ For Musepack support. ...@@ -57,6 +61,15 @@ For Musepack support.
MikMod - http://mikmod.raphnet.net/ MikMod - http://mikmod.raphnet.net/
For MOD support. You will need libmikmod. For MOD support. You will need libmikmod.
Optional Miscellaneous Dependencies
-----------------------------------
Avahi - http://www.avahi.org/
For Zeroconf support.
libsamplerate - http://www.mega-nerd.com/SRC/
For advanced samplerate conversions.
Download Download
-------- --------
...@@ -112,8 +125,7 @@ mp3's. ...@@ -112,8 +125,7 @@ mp3's.
Using MPD Using MPD
--------- ---------
You can download a web interface (phpMp) to MPD at <http://www.musicpd.org/>. You can download many different interfaces for MPD at
<http://mpd.wikia.com/wiki/Clients>
Also, several other clients can be found for MPD at <http://www.musicpd.org/>.
MPD can be interfaced directly using telnet (see COMMANDS, if you are brave). MPD can be interfaced directly using telnet (see COMMANDS, if you are brave).
Music Player Daemon (MPD) Music Player Daemon (MPD)
http://www.musicpd.org http://www.musicpd.org
A daemon for playing music (mp3, ogg vorbis, and flac). Music is played A daemon for playing music of various formats. Music is played through the
through the server's audio device. The daemon stores info about all available server's audio device. The daemon stores info about all available music,
music, and this info can be easily searched and retrieved. Player control, info and this info can be easily searched and retrieved. Player control, info
retrieval, and playlist management can all be managed remotely. retrieval, and playlist management can all be managed remotely.
To install MPD, see INSTALL. To install MPD, see INSTALL.
MPD includes 3 libraries in the source. libid3tag and libmad are released under MPD includes mp4ff in the source, due to licensing issues of the newer
the GPL and copyrighted by Robert Leslie (http://www.underbit.com/products/mad). version and includes bugfixes with the properly licensed version. mp4ff is
mp4ff is released under the GPL and copyrighted by M. Bakker, Ahead Software AG released under the GPL and copyrighted by M. Bakker, Ahead Software AG
(http://www.nero.com) and is distributed as a part of the FAAD2 - Freeware (http://www.nero.com) and is distributed as a part of the FAAD2 - Freeware
Advance Audio (AAC) Decoder. Advance Audio (AAC) Decoder.
MPD is released under the GNU Public License. MPD is released under the GNU Public License.
......
0.13 0.14
---- ----
*) data structures *) data structures
...@@ -16,7 +16,7 @@ ...@@ -16,7 +16,7 @@
*) cleanup linked list code! *) cleanup linked list code!
*) implement listener socket protocol as documented here: *) implement listener socket protocol as documented here:
http://www.musicpd.org/wiki/moin.cgi/MpdListenerProtocol http://mpd.wikia.com/wiki/MusicPlayerDaemonListenerProtocol
*) support for dynamically loading plugins *) support for dynamically loading plugins
*) cleanup input plugins "API" *) cleanup input plugins "API"
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
*) audio output *) audio output
*) write a esd native audioOutput *) write a esd native audioOutput
*) write a nas native audioOutput *) write a nas native audioOutput
*) need better resampling code
*) allowing "pausing" of audio output devices *) allowing "pausing" of audio output devices
*) while pausing, play silence for the devices that don't support *) while pausing, play silence for the devices that don't support
"pausing" "pausing"
...@@ -41,17 +40,8 @@ ...@@ -41,17 +40,8 @@
*) abstract out state code from playlist.c *) abstract out state code from playlist.c
*) put MPD Version in statefile *) put MPD Version in statefile
*) rewrite saved playlist code *) add playlistreplace command (replace current playlist with saved playlist
*) abstract out saved playlists from playlist.c and keep playing)
*) command for displaying playlist contents
*) command for appending to playlist
*) new commands
*) clear <playlist> /* synonym for rm */
*) add <playlist> <path>
*) playlist <playlist> /* displays saved playlist */
*) replace <playlist> /* replace current playlist
with saved playlist and
keep playing */
*) add command for inserting songs in a specific position *) add command for inserting songs in a specific position
...@@ -61,7 +51,7 @@ ...@@ -61,7 +51,7 @@
*) bug fixes *) bug fixes
post-1.0 post-1.0
---- --------
*) rewrite audio pipe *) rewrite audio pipe
*) use pthreads/clone *) use pthreads/clone
......
Music Player Daemon (MPD) - UPGRADING Music Player Daemon (MPD) - UPGRADING
Upgrading to 0.13.0
-------------------
JACK, Avahi, and libsamplerate have been added as optional dependencies.
FLAC/OggFLAC now supports the 1.1.3 API, and libmikmod 3.2.0 betas are
supported as well.
New mpd.conf parameters include zeroconf_name, samplerate_converter, and
gapless_mp3_playback. See the mpd.conf man page or updated mpconf.example for
more information on these parameters.
Support for the ID3v2 "Original Artist/Performer" tag has been added. Your
MP3s will need to be rescanned for these tags to be included in the database.
This can be done by running mpd --create-db.
Upgrading to 0.12.0 Upgrading to 0.12.0
------------------- -------------------
......
...@@ -756,6 +756,46 @@ AC_CONFIG_COMMANDS_PRE( ...@@ -756,6 +756,46 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.]) Usually this means the macro was only invoked conditionally.])
fi])]) fi])])
# serial 2
# AM_PROG_CC_C_O
# --------------
# Like AC_PROG_CC_C_O, but changed for automake.
# Copyright 1999, 2000, 2001 Free Software Foundation, Inc.
# 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, 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.
AC_DEFUN([AM_PROG_CC_C_O],
[AC_REQUIRE([AC_PROG_CC_C_O])dnl
AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
# FIXME: we rely on the cache variable name because
# there is no other way.
set dummy $CC
ac_cc=`echo $[2] | sed ['s/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/']`
if eval "test \"`echo '$ac_cv_prog_cc_'${ac_cc}_c_o`\" != yes"; then
# Losing compiler, so override with the script.
# FIXME: It is wrong to rewrite CC.
# But if we don't then we get into trouble of one sort or another.
# A longer-term fix would be to have automake use am__CC in this case,
# and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
CC="$am_aux_dir/compile $CC"
fi
])
# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*- # libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
# serial 48 AC_PROG_LIBTOOL # serial 48 AC_PROG_LIBTOOL
...@@ -8066,7 +8106,7 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile ...@@ -8066,7 +8106,7 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile
elif test "x$libFLAC_prefix" != "x" ; then elif test "x$libFLAC_prefix" != "x" ; then
LIBFLAC_LIBS="-L$libFLAC_prefix/lib" LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
elif test "x$prefix" != "xNONE" ; then elif test "x$prefix" != "xNONE" ; then
LIBFLAC_LIBS="-L$prefix/lib" LIBFLAC_LIBS="-L$libdir"
fi fi
LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC -lm" LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC -lm"
...@@ -8075,8 +8115,8 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile ...@@ -8075,8 +8115,8 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile
LIBFLAC_CFLAGS="-I$libFLAC_includes" LIBFLAC_CFLAGS="-I$libFLAC_includes"
elif test "x$libFLAC_prefix" != "x" ; then elif test "x$libFLAC_prefix" != "x" ; then
LIBFLAC_CFLAGS="-I$libFLAC_prefix/include" LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
elif test "x$prefix" != "xNONE"; then elif test "$prefix" != "xNONE"; then
LIBFLAC_CFLAGS="-I$prefix/include" LIBFLAC_CFLAGS="-I$libdir"
fi fi
AC_MSG_CHECKING(for libFLAC) AC_MSG_CHECKING(for libFLAC)
......
...@@ -9,6 +9,9 @@ ...@@ -9,6 +9,9 @@
/* Define for audiofile support */ /* Define for audiofile support */
#undef HAVE_AUDIOFILE #undef HAVE_AUDIOFILE
/* Define to enable Avahi Zeroconf support */
#undef HAVE_AVAHI
/* Define to 1 if you have the <dlfcn.h> header file. */ /* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H #undef HAVE_DLFCN_H
...@@ -49,6 +52,9 @@ ...@@ -49,6 +52,9 @@
/* Define if IPv6 support present */ /* Define if IPv6 support present */
#undef HAVE_IPV6 #undef HAVE_IPV6
/* Define to enable JACK support */
#undef HAVE_JACK
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */ /* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
#undef HAVE_LANGINFO_CODESET #undef HAVE_LANGINFO_CODESET
...@@ -58,6 +64,9 @@ ...@@ -58,6 +64,9 @@
/* Define to 1 if you have the `FLAC' library (-lFLAC). */ /* Define to 1 if you have the `FLAC' library (-lFLAC). */
#undef HAVE_LIBFLAC #undef HAVE_LIBFLAC
/* Define to enable libsamplerate */
#undef HAVE_LIBSAMPLERATE
/* Define if locale.h is present */ /* Define if locale.h is present */
#undef HAVE_LOCALE #undef HAVE_LOCALE
...@@ -94,7 +103,7 @@ ...@@ -94,7 +103,7 @@
/* Define for compiling OS X support */ /* Define for compiling OS X support */
#undef HAVE_OSX #undef HAVE_OSX
/* Define to enable PulseAudio */ /* Define to enable PulseAudio support */
#undef HAVE_PULSE #undef HAVE_PULSE
/* Define to 1 if you have the `setenv' function. */ /* Define to 1 if you have the `setenv' function. */
...@@ -118,9 +127,6 @@ ...@@ -118,9 +127,6 @@
/* Define to 1 if you have the <string.h> header file. */ /* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H #undef HAVE_STRING_H
/* Define to enable SUN audio support */
#undef HAVE_SUN
/* Define if sys/inttypes.h present */ /* Define if sys/inttypes.h present */
#undef HAVE_SYS_INTTYPES_H #undef HAVE_SYS_INTTYPES_H
...@@ -136,6 +142,9 @@ ...@@ -136,6 +142,9 @@
/* Define to 1 if you have the <unistd.h> header file. */ /* Define to 1 if you have the <unistd.h> header file. */
#undef HAVE_UNISTD_H #undef HAVE_UNISTD_H
/* Define to 1 if your C compiler doesn't accept -c and -o together. */
#undef NO_MINUS_C_MINUS_O
/* Name of package */ /* Name of package */
#undef PACKAGE #undef PACKAGE
......
...@@ -71,6 +71,11 @@ reports from what address a connection is opened, and when it is closed, and ...@@ -71,6 +71,11 @@ reports from what address a connection is opened, and when it is closed, and
"verbose" records excessive amounts of information for debugging purposes. The "verbose" records excessive amounts of information for debugging purposes. The
default is "default". default is "default".
.TP .TP
.B zeroconf_name <name>
If Zerconf is compiled into MPD, this is the service name to publish. This
should be unique to your local network, but name collisions will be properly
dealt with.
.TP
.B password <password@permissions> .B password <password@permissions>
This specifies a password for access to mpd. The format is This specifies a password for access to mpd. The format is
"password@permissions" where permissions is a comma delimited list composed "password@permissions" where permissions is a comma delimited list composed
...@@ -100,6 +105,39 @@ their own audio format which will be used for actual output to the audio ...@@ -100,6 +105,39 @@ their own audio format which will be used for actual output to the audio
device. An example is "44100:16:2" for 44100Hz, 16 bits, and 2 channels. The device. An example is "44100:16:2" for 44100Hz, 16 bits, and 2 channels. The
default is to use the audio format of the input file. default is to use the audio format of the input file.
.TP .TP
.B samplerate_converter <integer or prefix>
This specifies the libsamplerate converter to use. The supplied value should
either be an integer or a prefix of the name of a converter. The default is
"Fastest Sinc Interpolator".
At the time of this writing, the following converters are available:
.RS
.TP
Best Sinc Interpolator (0)
Band limited sinc interpolation, best quality, 97dB SNR, 96% BW.
.TP
Medium Sinc Interpolator (1)
Band limited sinc interpolation, medium quality, 97dB SNR, 90% BW.
.TP
Fastest Sinc Interpolator (2)
Band limited sinc interpolation, fastest, 97dB SNR, 80% BW.
.TP
ZOH Interpolator (3)
Zero order hold interpolator, very fast, very poor quality with audible
distortions.
.TP
Linear Interpolator (4)
Linear interpolator, very fast, poor quality.
.RE
.IP
For an up-to-date list of available converters, please see the libsamplerate
documentation (available online at <\fBhttp://www.mega-nerd.com/SRC/\fP>).
.TP
.B mixer_type <oss, alsa or software> .B mixer_type <oss, alsa or software>
This specifies which mixer to use. The default depends on what audio output This specifies which mixer to use. The default depends on what audio output
support mpd was built with. support mpd was built with.
...@@ -124,15 +162,17 @@ Musepack, and MP3 (through ID3v2 ReplayGain tags, not APEv2) are supported. ...@@ -124,15 +162,17 @@ Musepack, and MP3 (through ID3v2 ReplayGain tags, not APEv2) are supported.
This is the gain (in dB) applied to songs with ReplayGain tags. This is the gain (in dB) applied to songs with ReplayGain tags.
.TP .TP
.B volume_normalization <yes or no> .B volume_normalization <yes or no>
If yes, mpd will normalize the volume of songs as they play. Default is no. If yes, mpd will normalize the volume of songs as they play. The default is no.
.TP .TP
.B audio_buffer_size <size in KiB> .B audio_buffer_size <size in KiB>
This specifies the size of the audio output buffer that mpd uses. The default This specifies the size of the audio buffer in kibibytes. The default is 2048,
is 2048. large enough for nearly 12 seconds of CD-quality audio.
.TP .TP
.B buffer_before_play <0-100%> .B buffer_before_play <0-100%>
This specifies the amount of the audio buffer that will be filled before a song This specifies how much of the audio buffer should be filled before playing a
begins playing. The default is 25%. song. Try increasing this if you hear skipping when manually changing songs.
The default is 10%, a little over 1 second of CD-quality audio with the default
buffer size.
.TP .TP
.B http_buffer_size <size in KiB> .B http_buffer_size <size in KiB>
This specifies the size of the buffer used for playing HTTP streams. The This specifies the size of the buffer used for playing HTTP streams. The
...@@ -184,8 +224,20 @@ supported character sets can be obtained by running "iconv -l". The default is ...@@ -184,8 +224,20 @@ supported character sets can be obtained by running "iconv -l". The default is
to let libid3tag convert them (from ISO-8859-1, as the standard specifies) and to let libid3tag convert them (from ISO-8859-1, as the standard specifies) and
do no additional conversion. do no additional conversion.
.TP .TP
.B gapless_mp3_playback <yes or no>
This specifies whether to support gapless playback of MP3s which have the
necessary headers. Useful if your MP3s have headers with incorrect
information. If you have such MP3s, it is highly recommended that you fix them
using vbrfix (available from <http://www.willwap.co.uk/Programs/vbrfix.php>)
instead of disabling gapless MP3 playback. The default is to support gapless
MP3 playback.
.TP
.B save_absolute_paths_in_playlists <yes or no>
This specifies whether relative or absolute paths for song filenames are used
when saving playlists. The default is "no".
.TP
.B metadata_to_use <tags> .B metadata_to_use <tags>
This specifies the song metadata that will be scanned and made available to This specifies the tag types that will be scanned for and made available to
clients. Note that you must recreate (not update) your database for changes to clients. Note that you must recreate (not update) your database for changes to
this parameter to take effect. Possible values are artist, album, title, this parameter to take effect. Possible values are artist, album, title,
track, name, genre, date, composer, performer, comment, and disc. Multiple track, name, genre, date, composer, performer, comment, and disc. Multiple
...@@ -193,10 +245,6 @@ tags may be specified as a comma separated list. An example value is ...@@ -193,10 +245,6 @@ tags may be specified as a comma separated list. An example value is
"artist,album,title,track". The special value "none" may be used alone to "artist,album,title,track". The special value "none" may be used alone to
disable all metadata. The default is to use all known tag types except for disable all metadata. The default is to use all known tag types except for
comments. comments.
.TP
.B save_absolute_paths_in_playlists <yes or no>
This specifies whether relative or absolute paths for song filenames are used
when saving playlists. The default is "no".
.SH REQUIRED AUDIO OUTPUT PARAMETERS .SH REQUIRED AUDIO OUTPUT PARAMETERS
.TP .TP
.B type <type> .B type <type>
...@@ -215,11 +263,12 @@ whatever audio format is passed to the audio output. ...@@ -215,11 +263,12 @@ whatever audio format is passed to the audio output.
.SH OPTIONAL ALSA OUTPUT PARAMETERS .SH OPTIONAL ALSA OUTPUT PARAMETERS
.TP .TP
.B device <dev> .B device <dev>
This specifies the device to use for audio output. The default is "hw:0,0". This specifies the device to use for audio output. The default is "default".
.TP .TP
.B use_mmap <yes or no> .B use_mmap <yes or no>
Setting this allows you to use memory-mapped I/O. Certain hardware setups may Setting this allows you to use memory-mapped I/O. Certain hardware setups may
benefit from this, but most do not. Most users do not need to set this. benefit from this, but most do not. Most users do not need to set this. The
default is to not use memory-mapped I/O.
.TP .TP
.B buffer_time <time in microseconds> .B buffer_time <time in microseconds>
This sets the length of the hardware sample buffer in microseconds. Increasing This sets the length of the hardware sample buffer in microseconds. Increasing
...@@ -246,6 +295,20 @@ default is to let PulseAudio choose a server. ...@@ -246,6 +295,20 @@ default is to let PulseAudio choose a server.
.TP .TP
.B sink <sink> .B sink <sink>
The sink to output to. The default is to let PulseAudio choose a sink. The sink to output to. The default is to let PulseAudio choose a sink.
.SH REQUIRED JACK OUTPUT PARAMETERS
.TP
.B name <name>
The client name to use when connecting to JACK. The output ports <name>:left
and <name>:right will also be created for the left and right channels,
respectively.
.SH OPTIONAL JACK OUTPUT PARAMETERS
.TP
.B ports <left_port,right_port>
This specifies the left and right ports to connect to for the left and right
channels, respectively. The default is to let JACK choose a pair of ports.
.TP
.B ringbuffer_size <size in bytes>
This specifies the size of the ringbuffer in bytes. The default is 32768.
.SH OPTIONAL AO OUTPUT PARAMETERS .SH OPTIONAL AO OUTPUT PARAMETERS
.TP .TP
.B driver <driver> .B driver <driver>
......
...@@ -45,6 +45,12 @@ error_file "~/.mpd/mpd.error" ...@@ -45,6 +45,12 @@ error_file "~/.mpd/mpd.error"
# #
#log_level "default" #log_level "default"
# #
# If Zeroconf is configured, the service name to publish. This
# should be unique on your local network, but name collisions
# will be taken care of for you.
#
#zeroconf_name "Music Player"
#
################################################################ ################################################################
...@@ -117,6 +123,13 @@ error_file "~/.mpd/mpd.error" ...@@ -117,6 +123,13 @@ error_file "~/.mpd/mpd.error"
# #
#audio_output_format "44100:16:2" #audio_output_format "44100:16:2"
# #
# If MPD has been compiled with libsamplerate support, this
# specifies the sample rate converter to use. Possible
# values can be found in the mpd.conf man page or the
# libsamplerate documentation.
#
#samplerate_converter "Fastest Sinc Interpolator"
#
################################################################ ################################################################
...@@ -175,8 +188,9 @@ error_file "~/.mpd/mpd.error" ...@@ -175,8 +188,9 @@ error_file "~/.mpd/mpd.error"
#audio_buffer_size "2048" #audio_buffer_size "2048"
# #
# How much of the buffer to fill before beginning to play. # How much of the buffer to fill before beginning to play.
# Increase this if you hear skipping when changing songs.
# #
#buffer_before_play "0%" #buffer_before_play "10%"
# #
# Similar options for the HTTP stream buffer. If you hear # Similar options for the HTTP stream buffer. If you hear
# skipping while playing HTTP streams, you may wish to increase # skipping while playing HTTP streams, you may wish to increase
...@@ -233,13 +247,22 @@ error_file "~/.mpd/mpd.error" ...@@ -233,13 +247,22 @@ error_file "~/.mpd/mpd.error"
######################### OTHER OPTIONS ######################## ######################### OTHER OPTIONS ########################
# #
# The metadata types MPD will recognize. # Try disabling this if you have MP3s which appear to end
# abruptly. If this solves the problem, it is highly
# recommended that you fix your MP3s with vbrfix (available from
# <http://www.willwap.co.uk/Programs/vbrfix.php>), at which
# point you can re-enable support for gapless MP3 playback.
# #
#metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc" #gapless_mp3_playback "yes"
# #
# Enable this if you wish to use your MPD created playlists in # Enable this if you wish to use your MPD created playlists in
# other music players. # other music players.
# #
#save_absolute_paths_in_playlists "no" #save_absolute_paths_in_playlists "no"
# #
# A list of tag types that MPD will scan for and make available
# to clients.
#
#metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc"
#
################################################################ ################################################################
...@@ -8,7 +8,8 @@ mpd_audioOutputs = \ ...@@ -8,7 +8,8 @@ mpd_audioOutputs = \
audioOutputs/audioOutput_osx.c \ audioOutputs/audioOutput_osx.c \
audioOutputs/audioOutput_pulse.c \ audioOutputs/audioOutput_pulse.c \
audioOutputs/audioOutput_mvp.c \ audioOutputs/audioOutput_mvp.c \
audioOutputs/audioOutput_shout.c audioOutputs/audioOutput_shout.c \
audioOutputs/audioOutput_jack.c
mpd_inputPlugins = \ mpd_inputPlugins = \
inputPlugins/_flac_common.c \ inputPlugins/_flac_common.c \
...@@ -71,7 +72,11 @@ mpd_headers = \ ...@@ -71,7 +72,11 @@ mpd_headers = \
tree.h \ tree.h \
utf8.h \ utf8.h \
utils.h \ utils.h \
volume.h volume.h \
ioops.h \
zeroconf.h \
locate.h \
storedPlaylist.h
mpd_SOURCES = \ mpd_SOURCES = \
...@@ -120,7 +125,10 @@ mpd_SOURCES = \ ...@@ -120,7 +125,10 @@ mpd_SOURCES = \
tree.c \ tree.c \
utils.c \ utils.c \
volume.c \ volume.c \
utf8.c utf8.c \
zeroconf.c \
locate.c \
storedPlaylist.c
mpd_CFLAGS = $(MPD_CFLAGS) mpd_CFLAGS = $(MPD_CFLAGS)
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -39,12 +39,12 @@ ...@@ -39,12 +39,12 @@
#define AUDIO_DEVICE_STATE_LEN 19 /* strlen(AUDIO_DEVICE_STATE) */ #define AUDIO_DEVICE_STATE_LEN 19 /* strlen(AUDIO_DEVICE_STATE) */
#define AUDIO_BUFFER_SIZE 2*MAXPATHLEN #define AUDIO_BUFFER_SIZE 2*MAXPATHLEN
static AudioFormat audio_format = { 0, 0, 0 }; static AudioFormat audio_format;
static AudioFormat *audio_configFormat = NULL; static AudioFormat *audio_configFormat;
static AudioOutput *audioOutputArray = NULL; static AudioOutput *audioOutputArray;
static mpd_uint8 audioOutputArraySize = 0; static mpd_uint8 audioOutputArraySize;
#define DEVICE_OFF 0x00 #define DEVICE_OFF 0x00
#define DEVICE_ENABLE 0x01 /* currently off, but to be turned on */ #define DEVICE_ENABLE 0x01 /* currently off, but to be turned on */
...@@ -53,13 +53,13 @@ static mpd_uint8 audioOutputArraySize = 0; ...@@ -53,13 +53,13 @@ static mpd_uint8 audioOutputArraySize = 0;
/* the audioEnabledArray should be stuck into shared memory, and then disable /* the audioEnabledArray should be stuck into shared memory, and then disable
and enable in playAudio() routine */ and enable in playAudio() routine */
static mpd_uint8 *audioDeviceStates = NULL; static mpd_uint8 *audioDeviceStates;
static mpd_uint8 audioOpened = 0; static mpd_uint8 audioOpened;
static mpd_sint32 audioBufferSize = 0; static mpd_sint32 audioBufferSize;
static char *audioBuffer = NULL; static char *audioBuffer;
static mpd_sint32 audioBufferPos = 0; static mpd_sint32 audioBufferPos;
size_t audio_device_count(void) size_t audio_device_count(void)
{ {
...@@ -89,14 +89,6 @@ int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2) ...@@ -89,14 +89,6 @@ int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2)
return 1; return 1;
} }
extern AudioOutputPlugin alsaPlugin;
extern AudioOutputPlugin aoPlugin;
extern AudioOutputPlugin ossPlugin;
extern AudioOutputPlugin osxPlugin;
extern AudioOutputPlugin pulsePlugin;
extern AudioOutputPlugin mvpPlugin;
extern AudioOutputPlugin shoutPlugin;
void loadAudioDrivers(void) void loadAudioDrivers(void)
{ {
initAudioOutputPlugins(); initAudioOutputPlugins();
...@@ -107,6 +99,7 @@ void loadAudioDrivers(void) ...@@ -107,6 +99,7 @@ void loadAudioDrivers(void)
loadAudioOutputPlugin(&pulsePlugin); loadAudioOutputPlugin(&pulsePlugin);
loadAudioOutputPlugin(&mvpPlugin); loadAudioOutputPlugin(&mvpPlugin);
loadAudioOutputPlugin(&shoutPlugin); loadAudioOutputPlugin(&shoutPlugin);
loadAudioOutputPlugin(&jackPlugin);
} }
/* make sure initPlayerData is called before this function!! */ /* make sure initPlayerData is called before this function!! */
...@@ -134,23 +127,21 @@ void initAudioDriver(void) ...@@ -134,23 +127,21 @@ void initAudioDriver(void)
if (!initAudioOutput(output, param)) { if (!initAudioOutput(output, param)) {
if (param) if (param)
{ {
ERROR("problems configuring output device " FATAL("problems configuring output device "
"defined at line %i\n", param->line); "defined at line %i\n", param->line);
} }
else else
{ {
ERROR("No audio_output specified and unable to " FATAL("No audio_output specified and unable to "
"detect a default audio output device\n"); "detect a default audio output device\n");
} }
exit(EXIT_FAILURE);
} }
/* require output names to be unique: */ /* require output names to be unique: */
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
if (!strcmp(output->name, audioOutputArray[j].name)) { if (!strcmp(output->name, audioOutputArray[j].name)) {
ERROR("output devices with identical " FATAL("output devices with identical "
"names: %s\n", output->name); "names: %s\n", output->name);
exit(EXIT_FAILURE);
} }
} }
audioDeviceStates[i] = DEVICE_ENABLE; audioDeviceStates[i] = DEVICE_ENABLE;
...@@ -176,9 +167,8 @@ void initAudioConfig(void) ...@@ -176,9 +167,8 @@ void initAudioConfig(void)
audio_configFormat = xmalloc(sizeof(AudioFormat)); audio_configFormat = xmalloc(sizeof(AudioFormat));
if (0 != parseAudioConfig(audio_configFormat, param->value)) { if (0 != parseAudioConfig(audio_configFormat, param->value)) {
ERROR("error parsing \"%s\" at line %i\n", FATAL("error parsing \"%s\" at line %i\n",
CONF_AUDIO_OUTPUT_FORMAT, param->line); CONF_AUDIO_OUTPUT_FORMAT, param->line);
exit(EXIT_FAILURE);
} }
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -58,10 +58,9 @@ void finishAudioOutputPlugins(void) ...@@ -58,10 +58,9 @@ void finishAudioOutputPlugins(void)
#define getBlockParam(name, str, force) { \ #define getBlockParam(name, str, force) { \
bp = getBlockParam(param, name); \ bp = getBlockParam(param, name); \
if(force && bp == NULL) { \ if(force && bp == NULL) { \
ERROR("couldn't find parameter \"%s\" in audio output " \ FATAL("couldn't find parameter \"%s\" in audio output " \
"definition beginning at %i\n", \ "definition beginning at %i\n", \
name, param->line); \ name, param->line); \
exit(EXIT_FAILURE); \
} \ } \
if(bp) str = bp->value; \ if(bp) str = bp->value; \
} }
...@@ -81,9 +80,8 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param) ...@@ -81,9 +80,8 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0); getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
if (!findInList(audioOutputPluginList, type, &data)) { if (!findInList(audioOutputPluginList, type, &data)) {
ERROR("couldn't find audio output plugin for type " FATAL("couldn't find audio output plugin for type "
"\"%s\" at line %i\n", type, param->line); "\"%s\" at line %i\n", type, param->line);
exit(EXIT_FAILURE);
} }
plugin = (AudioOutputPlugin *) data; plugin = (AudioOutputPlugin *) data;
...@@ -135,13 +133,13 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param) ...@@ -135,13 +133,13 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
memset(&ao->inAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->outAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->outAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat)); memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->convState, 0, sizeof(ConvState));
if (format) { if (format) {
ao->convertAudioFormat = 1; ao->convertAudioFormat = 1;
if (0 != parseAudioConfig(&ao->reqAudioFormat, format)) { if (0 != parseAudioConfig(&ao->reqAudioFormat, format)) {
ERROR("error parsing format at line %i\n", bp->line); FATAL("error parsing format at line %i\n", bp->line);
exit(EXIT_FAILURE);
} }
copyAudioFormat(&ao->outAudioFormat, &ao->reqAudioFormat); copyAudioFormat(&ao->outAudioFormat, &ao->reqAudioFormat);
...@@ -155,33 +153,38 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param) ...@@ -155,33 +153,38 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat)
{ {
int ret; int ret = 0;
if (audioOutput->open) { if (audioOutput->open)
if (cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat) {
== 0) { if (0==cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat))
{
return 0; return 0;
} }
closeAudioOutput(audioOutput);
} }
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat); copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
if (audioOutput->convertAudioFormat) { if (audioOutput->convertAudioFormat)
{
copyAudioFormat(&audioOutput->outAudioFormat, copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->reqAudioFormat); &audioOutput->reqAudioFormat);
} else { }
else
{
copyAudioFormat(&audioOutput->outAudioFormat, copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->inAudioFormat); &audioOutput->inAudioFormat);
if (audioOutput->open) closeAudioOutput(audioOutput);
} }
ret = audioOutput->openDeviceFunc(audioOutput); if (!audioOutput->open)
{
ret = audioOutput->openDeviceFunc(audioOutput);
}
if (cmpAudioFormat(&audioOutput->inAudioFormat, audioOutput->sameInAndOutFormats =
&audioOutput->outAudioFormat) == 0) { !cmpAudioFormat(&audioOutput->inAudioFormat,
audioOutput->sameInAndOutFormats = 1; &audioOutput->outAudioFormat);
} else
audioOutput->sameInAndOutFormats = 0;
return ret; return ret;
} }
...@@ -189,12 +192,9 @@ int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat) ...@@ -189,12 +192,9 @@ int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat)
static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr, static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
int *sizeArgPtr) int *sizeArgPtr)
{ {
int size = int size = pcm_sizeOfConvBuffer(&(audioOutput->inAudioFormat),
pcm_sizeOfOutputBufferForAudioFormatConversion(& *sizeArgPtr,
(audioOutput-> &(audioOutput->outAudioFormat));
inAudioFormat),
*sizeArgPtr,
&(audioOutput->outAudioFormat));
if (size > audioOutput->convBufferLen) { if (size > audioOutput->convBufferLen) {
audioOutput->convBuffer = audioOutput->convBuffer =
...@@ -202,11 +202,12 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr, ...@@ -202,11 +202,12 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
audioOutput->convBufferLen = size; audioOutput->convBufferLen = size;
} }
pcm_convertAudioFormat(&(audioOutput->inAudioFormat), *chunkArgPtr, *sizeArgPtr = pcm_convertAudioFormat(&(audioOutput->inAudioFormat),
*sizeArgPtr, &(audioOutput->outAudioFormat), *chunkArgPtr, *sizeArgPtr,
audioOutput->convBuffer); &(audioOutput->outAudioFormat),
audioOutput->convBuffer,
&audioOutput->convState);
*sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer; *chunkArgPtr = audioOutput->convBuffer;
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -21,24 +21,14 @@ ...@@ -21,24 +21,14 @@
#include "../config.h" #include "../config.h"
#include "pcm_utils.h"
#include "mpd_types.h" #include "mpd_types.h"
#include "audio.h" #include "audio.h"
#include "tag.h" #include "tag.h"
#include "conf.h" #include "conf.h"
#include "utils.h" #include "utils.h"
#define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) \ #define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) AudioOutputPlugin plugin;
AudioOutputPlugin plugin = { \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL \
};
typedef struct _AudioOutput AudioOutput; typedef struct _AudioOutput AudioOutput;
...@@ -77,6 +67,7 @@ struct _AudioOutput { ...@@ -77,6 +67,7 @@ struct _AudioOutput {
AudioFormat inAudioFormat; AudioFormat inAudioFormat;
AudioFormat outAudioFormat; AudioFormat outAudioFormat;
AudioFormat reqAudioFormat; AudioFormat reqAudioFormat;
ConvState convState;
char *convBuffer; char *convBuffer;
int convBufferLen; int convBufferLen;
int sameInAndOutFormats; int sameInAndOutFormats;
...@@ -113,4 +104,14 @@ int keepAudioOutputAlive(AudioOutput * audioOutput, int ms); ...@@ -113,4 +104,14 @@ int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag); void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag);
void printAllOutputPluginTypes(FILE * fp); void printAllOutputPluginTypes(FILE * fp);
extern AudioOutputPlugin alsaPlugin;
extern AudioOutputPlugin aoPlugin;
extern AudioOutputPlugin ossPlugin;
extern AudioOutputPlugin osxPlugin;
extern AudioOutputPlugin pulsePlugin;
extern AudioOutputPlugin mvpPlugin;
extern AudioOutputPlugin shoutPlugin;
extern AudioOutputPlugin jackPlugin;
#endif #endif
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -34,11 +34,8 @@ ...@@ -34,11 +34,8 @@
#include "../conf.h" #include "../conf.h"
#include "../log.h" #include "../log.h"
#include "../sig_handlers.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
...@@ -88,8 +85,7 @@ static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -88,8 +85,7 @@ static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param)
ad->device = bp ? xstrdup(bp->value) : xstrdup("default"); ad->device = bp ? xstrdup(bp->value) : xstrdup("default");
if ((bp = getBlockParam(param, "use_mmap")) && if ((bp = getBlockParam(param, "use_mmap")) &&
(!strcasecmp(bp->value, "yes") || !strcasecmp(bp->value, "yes"))
!strcasecmp(bp->value, "true")))
ad->useMmap = 1; ad->useMmap = 1;
if ((bp = getBlockParam(param, "buffer_time"))) if ((bp = getBlockParam(param, "buffer_time")))
ad->buffer_time = atoi(bp->value); ad->buffer_time = atoi(bp->value);
...@@ -210,7 +206,7 @@ configure_hw: ...@@ -210,7 +206,7 @@ configure_hw:
err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat); err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
if (err < 0) { if (err < 0) {
ERROR("ALSA device \"%s\" does not support %i bit audio: " ERROR("ALSA device \"%s\" does not support %i bit audio: "
"%s\n", ad->device, (int)bitformat, snd_strerror(-err)); "%s\n", ad->device, audioFormat->bits, snd_strerror(-err));
goto fail; goto fail;
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -24,12 +24,10 @@ ...@@ -24,12 +24,10 @@
#include "../log.h" #include "../log.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
#include <ao/ao.h> #include <ao/ao.h>
static int driverInitCount = 0; static int driverInitCount;
typedef struct _AoData { typedef struct _AoData {
int writeSize; int writeSize;
...@@ -77,9 +75,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput, ...@@ -77,9 +75,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
if ((blockParam = getBlockParam(param, "write_size"))) { if ((blockParam = getBlockParam(param, "write_size"))) {
ad->writeSize = strtol(blockParam->value, &test, 10); 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", FATAL("\"%s\" is not a valid write size at line %i\n",
blockParam->value, blockParam->line); blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
} }
} else } else
ad->writeSize = 1024; ad->writeSize = 1024;
...@@ -94,16 +91,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput, ...@@ -94,16 +91,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
if (!blockParam || 0 == strcmp(blockParam->value, "default")) { if (!blockParam || 0 == strcmp(blockParam->value, "default")) {
ad->driverId = ao_default_driver_id(); 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", FATAL("\"%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 " FATAL("problems getting driver info for device defined at line %i\n"
"line %i\n", param->line); "you may not have permission to the audio device\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, DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
...@@ -122,11 +116,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput, ...@@ -122,11 +116,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
while (n1) { while (n1) {
stk2 = NULL; stk2 = NULL;
key = strtok_r(n1, "=", &stk2); key = strtok_r(n1, "=", &stk2);
if (!key) { if (!key)
ERROR("problems parsing " FATAL("problems parsing options \"%s\"\n", n1);
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
/*found = 0; /*found = 0;
for(i=0;i<ai->option_count;i++) { for(i=0;i<ai->option_count;i++) {
if(strcmp(ai->options[i],key)==0) { if(strcmp(ai->options[i],key)==0) {
...@@ -135,17 +126,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput, ...@@ -135,17 +126,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
} }
} }
if(!found) { if(!found) {
ERROR("\"%s\" is not an option for " FATAL("\"%s\" is not an option for "
"\"%s\" ao driver\n",key, "\"%s\" ao driver\n",key,
ai->short_name); ai->short_name);
exit(EXIT_FAILURE);
} */ } */
value = strtok_r(NULL, "", &stk2); value = strtok_r(NULL, "", &stk2);
if (!value) { if (!value)
ERROR("problems parsing " FATAL("problems parsing options \"%s\"\n", n1);
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
ao_append_option(&ad->options, key, value); ao_append_option(&ad->options, key, value);
n1 = strtok_r(NULL, ";", &stk1); n1 = strtok_r(NULL, ";", &stk1);
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Media MVP audio output based on code from MVPMC project: * Media MVP audio output based on code from MVPMC project:
...@@ -27,11 +27,8 @@ ...@@ -27,11 +27,8 @@
#include "../conf.h" #include "../conf.h"
#include "../log.h" #include "../log.h"
#include "../sig_handlers.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* OSS audio output (c) 2004, 2005, 2006 by Eric Wong <eric@petta-tech.com> * OSS audio output (c) 2004, 2005, 2006, 2007 by Eric Wong <eric@petta-tech.com>
* and Warren Dukes <warren.dukes@gmail.com> * and Warren Dukes <warren.dukes@gmail.com>
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -25,14 +25,10 @@ ...@@ -25,14 +25,10 @@
#ifdef HAVE_OSS #ifdef HAVE_OSS
#include "../utils.h"
#include "../conf.h" #include "../conf.h"
#include "../log.h" #include "../log.h"
#include "../sig_handlers.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/stat.h> #include <sys/stat.h>
...@@ -363,7 +359,7 @@ static int oss_open_default(AudioOutput *ao, ConfigParam *param, OssData *od) ...@@ -363,7 +359,7 @@ static int oss_open_default(AudioOutput *ao, ConfigParam *param, OssData *od)
} }
if (param) if (param)
ERROR("Error trying to open specified OSS device" ERROR("error trying to open specified OSS device"
" at line %i\n", param->line); " at line %i\n", param->line);
else else
ERROR("error trying to open default OSS device\n"); ERROR("error trying to open default OSS device\n");
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -25,7 +25,6 @@ ...@@ -25,7 +25,6 @@
#include <pthread.h> #include <pthread.h>
#include "../log.h" #include "../log.h"
#include "../utils.h"
typedef struct _OsxData { typedef struct _OsxData {
AudioUnit au; AudioUnit au;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -24,12 +24,9 @@ ...@@ -24,12 +24,9 @@
#include "../conf.h" #include "../conf.h"
#include "../log.h" #include "../log.h"
#include "../sig_handlers.h"
#include "../pcm_utils.h" #include "../pcm_utils.h"
#include <string.h> #include <string.h>
#include <assert.h>
#include <signal.h>
#include <time.h> #include <time.h>
#include <shout/shout.h> #include <shout/shout.h>
...@@ -37,7 +34,7 @@ ...@@ -37,7 +34,7 @@
#define CONN_ATTEMPT_INTERVAL 60 #define CONN_ATTEMPT_INTERVAL 60
static int shoutInitCount = 0; static int shoutInitCount;
/* lots of this code blatantly stolent from bossogg/bossao2 */ /* lots of this code blatantly stolent from bossogg/bossao2 */
...@@ -67,6 +64,7 @@ typedef struct _ShoutData { ...@@ -67,6 +64,7 @@ typedef struct _ShoutData {
int connAttempts; int connAttempts;
time_t lastAttempt; time_t lastAttempt;
int last_err;
/* just a pointer to audioOutput->outAudioFormat */ /* just a pointer to audioOutput->outAudioFormat */
AudioFormat *audioFormat; AudioFormat *audioFormat;
...@@ -85,6 +83,7 @@ static ShoutData *newShoutData(void) ...@@ -85,6 +83,7 @@ static ShoutData *newShoutData(void)
ret->connAttempts = 0; ret->connAttempts = 0;
ret->lastAttempt = 0; ret->lastAttempt = 0;
ret->audioFormat = NULL; ret->audioFormat = NULL;
ret->last_err = SHOUTERR_UNCONNECTED;
return ret; return ret;
} }
...@@ -101,10 +100,9 @@ static void freeShoutData(ShoutData * sd) ...@@ -101,10 +100,9 @@ static void freeShoutData(ShoutData * sd)
#define checkBlockParam(name) { \ #define checkBlockParam(name) { \
blockParam = getBlockParam(param, name); \ blockParam = getBlockParam(param, name); \
if(!blockParam) { \ if (!blockParam) { \
ERROR("no \"%s\" defined for shout device defined at line " \ FATAL("no \"%s\" defined for shout device defined at line " \
"%i\n", name, param->line); \ "%i\n", name, param->line); \
exit(EXIT_FAILURE); \
} \ } \
} }
...@@ -119,7 +117,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -119,7 +117,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
char *user; char *user;
char *name; char *name;
BlockParam *blockParam; BlockParam *blockParam;
unsigned int public; unsigned int public = 0;
sd = newShoutData(); sd = newShoutData();
...@@ -139,9 +137,8 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -139,9 +137,8 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
port = strtol(blockParam->value, &test, 10); port = strtol(blockParam->value, &test, 10);
if (*test != '\0' || port <= 0) { if (*test != '\0' || port <= 0) {
ERROR("shout port \"%s\" is not a positive integer, line %i\n", FATAL("shout port \"%s\" is not a positive integer, line %i\n",
blockParam->value, blockParam->line); blockParam->value, blockParam->line);
exit(EXIT_FAILURE);
} }
checkBlockParam("password"); checkBlockParam("password");
...@@ -152,17 +149,15 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -152,17 +149,15 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
blockParam = getBlockParam(param, "public"); blockParam = getBlockParam(param, "public");
if (blockParam) { if (blockParam) {
if (0 == strcmp(blockParam->value, "yes")) if (0 == strcmp(blockParam->value, "yes")) {
public = 1; public = 1;
else if (0 == strcmp(blockParam->value, "no")) } else if (0 == strcmp(blockParam->value, "no")) {
public = 0; public = 0;
else { } else {
ERROR("public \"%s\" is not \"yes\" or \"no\" at line " FATAL("public \"%s\" is not \"yes\" or \"no\" at line "
"%i\n", param->value, param->line); "%i\n", param->value, param->line);
exit(EXIT_FAILURE);
} }
} else }
public = 0;
blockParam = getBlockParam(param, "user"); blockParam = getBlockParam(param, "user");
if (blockParam) if (blockParam)
...@@ -178,35 +173,31 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -178,35 +173,31 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
sd->quality = strtod(blockParam->value, &test); sd->quality = strtod(blockParam->value, &test);
if (*test != '\0' || sd->quality < -1.0 || sd->quality > 10.0) { if (*test != '\0' || sd->quality < -1.0 || sd->quality > 10.0) {
ERROR("shout quality \"%s\" is not a number in the " FATAL("shout quality \"%s\" is not a number in the "
"range -1 to 10, line %i\n", blockParam->value, "range -1 to 10, line %i\n", blockParam->value,
blockParam->line); blockParam->line);
exit(EXIT_FAILURE);
} }
blockParam = getBlockParam(param, "bitrate"); blockParam = getBlockParam(param, "bitrate");
if (blockParam) { if (blockParam) {
ERROR("quality (line %i) and bitrate (line %i) are " FATAL("quality (line %i) and bitrate (line %i) are "
"both defined for shout output\n", line, "both defined for shout output\n", line,
blockParam->line); blockParam->line);
exit(EXIT_FAILURE);
} }
} else { } else {
blockParam = getBlockParam(param, "bitrate"); blockParam = getBlockParam(param, "bitrate");
if (!blockParam) { if (!blockParam) {
ERROR("neither bitrate nor quality defined for shout " FATAL("neither bitrate nor quality defined for shout "
"output at line %i\n", param->line); "output at line %i\n", param->line);
exit(EXIT_FAILURE);
} }
sd->bitrate = strtol(blockParam->value, &test, 10); sd->bitrate = strtol(blockParam->value, &test, 10);
if (*test != '\0' || sd->bitrate <= 0) { if (*test != '\0' || sd->bitrate <= 0) {
ERROR("bitrate at line %i should be a positive integer " FATAL("bitrate at line %i should be a positive integer "
"\n", blockParam->line); "\n", blockParam->line);
exit(EXIT_FAILURE);
} }
} }
...@@ -220,30 +211,28 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param) ...@@ -220,30 +211,28 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
shout_set_name(sd->shoutConn, name) != SHOUTERR_SUCCESS || shout_set_name(sd->shoutConn, name) != SHOUTERR_SUCCESS ||
shout_set_user(sd->shoutConn, user) != SHOUTERR_SUCCESS || shout_set_user(sd->shoutConn, user) != SHOUTERR_SUCCESS ||
shout_set_public(sd->shoutConn, public) != SHOUTERR_SUCCESS || shout_set_public(sd->shoutConn, public) != SHOUTERR_SUCCESS ||
shout_set_nonblocking(sd->shoutConn, 1) != SHOUTERR_SUCCESS ||
shout_set_format(sd->shoutConn, SHOUT_FORMAT_VORBIS) shout_set_format(sd->shoutConn, SHOUT_FORMAT_VORBIS)
!= SHOUTERR_SUCCESS || != SHOUTERR_SUCCESS ||
shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP) shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP)
!= SHOUTERR_SUCCESS || != SHOUTERR_SUCCESS ||
shout_set_agent(sd->shoutConn, "MPD") != SHOUTERR_SUCCESS) { shout_set_agent(sd->shoutConn, "MPD") != SHOUTERR_SUCCESS) {
ERROR("error configuring shout defined at line %i: %s\n", FATAL("error configuring shout defined at line %i: %s\n",
param->line, shout_get_error(sd->shoutConn)); param->line, shout_get_error(sd->shoutConn));
exit(EXIT_FAILURE);
} }
/* optional paramters */ /* optional paramters */
blockParam = getBlockParam(param, "genre"); blockParam = getBlockParam(param, "genre");
if (blockParam && shout_set_genre(sd->shoutConn, blockParam->value)) { if (blockParam && shout_set_genre(sd->shoutConn, blockParam->value)) {
ERROR("error configuring shout defined at line %i: %s\n", FATAL("error configuring shout defined at line %i: %s\n",
param->line, shout_get_error(sd->shoutConn)); param->line, shout_get_error(sd->shoutConn));
exit(EXIT_FAILURE);
} }
blockParam = getBlockParam(param, "description"); blockParam = getBlockParam(param, "description");
if (blockParam && shout_set_description(sd->shoutConn, if (blockParam && shout_set_description(sd->shoutConn,
blockParam->value)) { blockParam->value)) {
ERROR("error configuring shout defined at line %i: %s\n", FATAL("error configuring shout defined at line %i: %s\n",
param->line, shout_get_error(sd->shoutConn)); param->line, shout_get_error(sd->shoutConn));
exit(EXIT_FAILURE);
} }
{ {
...@@ -358,6 +347,7 @@ static void myShout_closeShoutConn(ShoutData * sd) ...@@ -358,6 +347,7 @@ static void myShout_closeShoutConn(ShoutData * sd)
} }
} }
sd->last_err = SHOUTERR_UNCONNECTED;
sd->opened = 0; sd->opened = 0;
} }
...@@ -460,9 +450,19 @@ static int myShout_openShoutConn(AudioOutput * audioOutput) ...@@ -460,9 +450,19 @@ static int myShout_openShoutConn(AudioOutput * audioOutput)
sd->connAttempts++; sd->connAttempts++;
sd->lastAttempt = t; if (sd->last_err == SHOUTERR_UNCONNECTED)
sd->last_err = shout_open(sd->shoutConn);
if (shout_open(sd->shoutConn) != SHOUTERR_SUCCESS) { switch (sd->last_err) {
case SHOUTERR_SUCCESS:
case SHOUTERR_CONNECTED:
break;
case SHOUTERR_BUSY:
sd->last_err = shout_get_connected(sd->shoutConn);
if (sd->last_err == SHOUTERR_CONNECTED)
break;
return -1;
default:
sd->lastAttempt = t;
ERROR("problem opening connection to shout server %s:%i " ERROR("problem opening connection to shout server %s:%i "
"(attempt %i): %s\n", "(attempt %i): %s\n",
shout_get_host(sd->shoutConn), shout_get_host(sd->shoutConn),
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -27,18 +27,18 @@ ...@@ -27,18 +27,18 @@
#ifdef HAVE_ICONV #ifdef HAVE_ICONV
#include <iconv.h> #include <iconv.h>
iconv_t char_conv_iconv; static iconv_t char_conv_iconv;
#endif #endif
char *char_conv_to = NULL; static char *char_conv_to;
char *char_conv_from = NULL; static char *char_conv_from;
mpd_sint8 char_conv_same = 0; static mpd_sint8 char_conv_same;
mpd_sint8 char_conv_use_iconv = 0; static mpd_sint8 char_conv_use_iconv;
/* 1 is to use latin1ToUtf8 /* 1 is to use latin1ToUtf8
0 is not to use latin1/utf8 converter 0 is not to use latin1/utf8 converter
-1 is to use utf8ToLatin1*/ -1 is to use utf8ToLatin1*/
mpd_sint8 char_conv_latin1ToUtf8 = 0; static mpd_sint8 char_conv_latin1ToUtf8;
#define BUFFER_SIZE 1024 #define BUFFER_SIZE 1024
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -28,9 +28,9 @@ ...@@ -28,9 +28,9 @@
#include "permission.h" #include "permission.h"
#include "buffer2array.h" #include "buffer2array.h"
#include "log.h" #include "log.h"
#include "dbUtils.h"
#include "tag.h" #include "tag.h"
#include "utils.h" #include "utils.h"
#include "storedPlaylist.h"
#include <assert.h> #include <assert.h>
#include <stdarg.h> #include <stdarg.h>
...@@ -92,6 +92,15 @@ ...@@ -92,6 +92,15 @@
#define COMMAND_DEVICES "outputs" #define COMMAND_DEVICES "outputs"
#define COMMAND_COMMANDS "commands" #define COMMAND_COMMANDS "commands"
#define COMMAND_NOTCOMMANDS "notcommands" #define COMMAND_NOTCOMMANDS "notcommands"
#define COMMAND_PLAYLISTCLEAR "playlistclear"
#define COMMAND_PLAYLISTADD "playlistadd"
#define COMMAND_PLAYLISTFIND "playlistfind"
#define COMMAND_PLAYLISTSEARCH "playlistsearch"
#define COMMAND_PLAYLISTMOVE "playlistmove"
#define COMMAND_PLAYLISTDELETE "playlistdelete"
#define COMMAND_TAGTYPES "tagtypes"
#define COMMAND_COUNT "count"
#define COMMAND_RENAME "rename"
#define COMMAND_STATUS_VOLUME "volume" #define COMMAND_STATUS_VOLUME "volume"
#define COMMAND_STATUS_STATE "state" #define COMMAND_STATUS_STATE "state"
...@@ -132,8 +141,8 @@ struct _CommandEntry { ...@@ -132,8 +141,8 @@ struct _CommandEntry {
CommandListHandlerFunction listHandler; CommandListHandlerFunction listHandler;
}; };
static char *current_command = NULL; static char *current_command;
static int command_listNum = 0; static int command_listNum;
static CommandEntry *getCommandEntryFromString(char *string, int *permission); static CommandEntry *getCommandEntryFromString(char *string, int *permission);
...@@ -174,6 +183,12 @@ static int handleUrlHandlers(int fd, int *permission, int argc, char *argv[]) ...@@ -174,6 +183,12 @@ static int handleUrlHandlers(int fd, int *permission, int argc, char *argv[])
return printRemoteUrlHandlers(fd); return printRemoteUrlHandlers(fd);
} }
static int handleTagTypes(int fd, int *permission, int argc, char *argv[])
{
printTagTypes(fd);
return 0;
}
static int handlePlay(int fd, int *permission, int argc, char *argv[]) static int handlePlay(int fd, int *permission, int argc, char *argv[])
{ {
int song = -1; int song = -1;
...@@ -388,17 +403,18 @@ static int handleListPlaylistInfo(int fd, int *permission, ...@@ -388,17 +403,18 @@ static int handleListPlaylistInfo(int fd, int *permission,
static int handleLsInfo(int fd, int *permission, int argc, char *argv[]) static int handleLsInfo(int fd, int *permission, int argc, char *argv[])
{ {
if (argc == 1) { char *path = "";
if (printDirectoryInfo(fd, NULL) < 0)
return -1; if (argc == 2)
else path = argv[1];
return lsPlaylists(fd, "");
} else { if (printDirectoryInfo(fd, path) < 0)
if (printDirectoryInfo(fd, argv[1]) < 0) return -1;
return -1;
else if (isRootDirectory(path))
return lsPlaylists(fd, argv[1]); return lsPlaylists(fd, path);
}
return 0;
} }
static int handleRm(int fd, int *permission, int argc, char *argv[]) static int handleRm(int fd, int *permission, int argc, char *argv[])
...@@ -406,6 +422,11 @@ static int handleRm(int fd, int *permission, int argc, char *argv[]) ...@@ -406,6 +422,11 @@ static int handleRm(int fd, int *permission, int argc, char *argv[])
return deletePlaylist(fd, argv[1]); return deletePlaylist(fd, argv[1]);
} }
static int handleRename(int fd, int *permission, int argc, char *argv[])
{
return renameStoredPlaylist(fd, argv[1], argv[2]);
}
static int handlePlaylistChanges(int fd, int *permission, static int handlePlaylistChanges(int fd, int *permission,
int argc, char *argv[]) int argc, char *argv[])
{ {
...@@ -508,13 +529,109 @@ static int handleSearch(int fd, int *permission, int argc, char *argv[]) ...@@ -508,13 +529,109 @@ static int handleSearch(int fd, int *permission, int argc, char *argv[])
return ret; return ret;
} }
static int handleCount(int fd, int *permission, int argc, char *argv[])
{
int ret;
LocateTagItem *items;
int numItems = newLocateTagItemArrayFromArgArray(argv + 1,
argc - 1,
&items);
if (numItems <= 0) {
commandError(fd, ACK_ERROR_ARG, "incorrect arguments");
return -1;
}
ret = searchStatsForSongsIn(fd, NULL, numItems, items);
freeLocateTagItemArray(numItems, items);
return ret;
}
static int handlePlaylistFind(int fd, int *permission, int argc, char *argv[])
{
LocateTagItem *items;
int numItems = newLocateTagItemArrayFromArgArray(argv + 1,
argc - 1,
&items);
if (numItems <= 0) {
commandError(fd, ACK_ERROR_ARG, "incorrect arguments");
return -1;
}
findSongsInPlaylist(fd, numItems, items);
freeLocateTagItemArray(numItems, items);
return 0;
}
static int handlePlaylistSearch(int fd, int *permission, int argc, char *argv[])
{
LocateTagItem *items;
int numItems = newLocateTagItemArrayFromArgArray(argv + 1,
argc - 1,
&items);
if (numItems <= 0) {
commandError(fd, ACK_ERROR_ARG, "incorrect arguments");
return -1;
}
searchForSongsInPlaylist(fd, numItems, items);
freeLocateTagItemArray(numItems, items);
return 0;
}
static int handlePlaylistDelete(int fd, int *permission, int argc, char *argv[]) {
char *playlist = argv[1];
int from;
char *test;
from = strtol(argv[2], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[2]);
return -1;
}
return removeOneSongFromStoredPlaylistByPath(fd, playlist, from);
}
static int handlePlaylistMove(int fd, int *permission, int argc, char *argv[])
{
char *playlist = argv[1];
int from, to;
char *test;
from = strtol(argv[2], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[2]);
return -1;
}
to = strtol(argv[3], &test, 10);
if (*test != '\0') {
commandError(fd, ACK_ERROR_ARG,
"\"%s\" is not a integer", argv[3]);
return -1;
}
return moveSongInStoredPlaylistByPath(fd, playlist, from, to);
}
static int listHandleUpdate(int fd, static int listHandleUpdate(int fd,
int *permission, int *permission,
int argc, int argc,
char *argv[], char *argv[],
struct strnode *cmdnode, CommandEntry * cmd) struct strnode *cmdnode, CommandEntry * cmd)
{ {
static List *pathList = NULL; static List *pathList;
CommandEntry *nextCmd = NULL; CommandEntry *nextCmd = NULL;
struct strnode *next = cmdnode->next; struct strnode *next = cmdnode->next;
...@@ -646,6 +763,12 @@ static int handleList(int fd, int *permission, int argc, char *argv[]) ...@@ -646,6 +763,12 @@ static int handleList(int fd, int *permission, int argc, char *argv[])
return -1; return -1;
} }
if (tagType == LOCATE_TAG_ANY_TYPE) {
commandError(fd, ACK_ERROR_ARG,
"\"any\" is not a valid return tag type");
return -1;
}
/* for compatibility with < 0.12.0 */ /* for compatibility with < 0.12.0 */
if (argc == 3) { if (argc == 3) {
if (tagType != TAG_ITEM_ALBUM) { if (tagType != TAG_ITEM_ALBUM) {
...@@ -917,6 +1040,22 @@ static int handleNotcommands(int fd, int *permission, int argc, char *argv[]) ...@@ -917,6 +1040,22 @@ static int handleNotcommands(int fd, int *permission, int argc, char *argv[])
return 0; return 0;
} }
static int handlePlaylistClear(int fd, int *permission, int argc, char *argv[])
{
return clearStoredPlaylist(fd, argv[1]);
}
static int handlePlaylistAdd(int fd, int *permission, int argc, char *argv[])
{
char *playlist = argv[1];
char *path = argv[2];
if (isRemoteUrl(path))
return addToStoredPlaylist(fd, path, playlist);
return addAllInToStoredPlaylist(fd, path, playlist);
}
void initCommands(void) void initCommands(void)
{ {
commandList = makeList(free, 1); commandList = makeList(free, 1);
...@@ -976,6 +1115,15 @@ void initCommands(void) ...@@ -976,6 +1115,15 @@ void initCommands(void)
addCommand(COMMAND_DEVICES, PERMISSION_READ, 0, 0, handleDevices, NULL); addCommand(COMMAND_DEVICES, PERMISSION_READ, 0, 0, handleDevices, NULL);
addCommand(COMMAND_COMMANDS, PERMISSION_NONE, 0, 0, handleCommands, NULL); addCommand(COMMAND_COMMANDS, PERMISSION_NONE, 0, 0, handleCommands, NULL);
addCommand(COMMAND_NOTCOMMANDS, PERMISSION_NONE, 0, 0, handleNotcommands, NULL); addCommand(COMMAND_NOTCOMMANDS, PERMISSION_NONE, 0, 0, handleNotcommands, NULL);
addCommand(COMMAND_PLAYLISTCLEAR, PERMISSION_CONTROL, 1, 1, handlePlaylistClear, NULL);
addCommand(COMMAND_PLAYLISTADD, PERMISSION_CONTROL, 2, 2, handlePlaylistAdd, NULL);
addCommand(COMMAND_PLAYLISTFIND, PERMISSION_READ, 2, -1, handlePlaylistFind, NULL);
addCommand(COMMAND_PLAYLISTSEARCH, PERMISSION_READ, 2, -1, handlePlaylistSearch, NULL);
addCommand(COMMAND_PLAYLISTMOVE, PERMISSION_CONTROL, 3, 3, handlePlaylistMove, NULL);
addCommand(COMMAND_PLAYLISTDELETE, PERMISSION_CONTROL, 2, 2, handlePlaylistDelete, NULL);
addCommand(COMMAND_TAGTYPES, PERMISSION_READ, 0, 0, handleTagTypes, NULL);
addCommand(COMMAND_COUNT, PERMISSION_READ, 2, -1, handleCount, NULL);
addCommand(COMMAND_RENAME, PERMISSION_CONTROL, 2, 2, handleRename, NULL);
sortList(commandList); sortList(commandList);
} }
...@@ -1134,15 +1282,18 @@ mpd_fprintf_ void commandError(int fd, int error, const char *fmt, ...) ...@@ -1134,15 +1282,18 @@ mpd_fprintf_ void commandError(int fd, int error, const char *fmt, ...)
va_list args; va_list args;
va_start(args, fmt); va_start(args, fmt);
if (current_command) { if (current_command && fd != STDERR_FILENO) {
fdprintf(fd, "ACK [%i@%i] {%s} ", fdprintf(fd, "ACK [%i@%i] {%s} ",
(int)error, command_listNum, current_command); (int)error, command_listNum, current_command);
vfdprintf(fd, fmt, args);
fdprintf(fd, "\n");
current_command = NULL; current_command = NULL;
} else } else {
fdprintf(STDERR_FILENO, "ACK [%i@%i] ", fdprintf(STDERR_FILENO, "ACK [%i@%i] ",
(int)error, command_listNum); (int)error, command_listNum);
vfdprintf(STDERR_FILENO, fmt, args);
fdprintf(STDERR_FILENO, "\n");
}
vfdprintf(fd, fmt, args);
va_end(args); va_end(args);
fdprintf(fd, "\n");
} }
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Compressor logic by * Compressor logic by
...@@ -39,7 +39,7 @@ static int screen; ...@@ -39,7 +39,7 @@ static int screen;
static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC; static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
#endif #endif
static int *peaks = NULL; static int *peaks;
static int gainCurrent, gainTarget; static int gainCurrent, gainTarget;
static struct { static struct {
...@@ -52,13 +52,13 @@ static struct { ...@@ -52,13 +52,13 @@ static struct {
} prefs; } prefs;
#ifdef USE_X #ifdef USE_X
static int mon_init = 0; static int mon_init;
#endif #endif
void CompressCfg(int show_mon, int anticlip, int target, int gainmax, void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
int gainsmooth, int buckets) int gainsmooth, int buckets)
{ {
static int lastsize = 0; static int lastsize;
prefs.show_mon = show_mon; prefs.show_mon = show_mon;
prefs.anticlip = anticlip; prefs.anticlip = anticlip;
...@@ -179,9 +179,9 @@ void CompressDo(void *data, unsigned int length) ...@@ -179,9 +179,9 @@ void CompressDo(void *data, unsigned int length)
int gr, gf, gn; int gr, gf, gn;
static int pn = -1; static int pn = -1;
#ifdef STATS #ifdef STATS
static int clip = 0; static int clip;
#endif #endif
static int clipped = 0; static int clipped;
if (!peaks) if (!peaks)
return; return;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* interface to audio compression * interface to audio compression
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -48,7 +48,7 @@ typedef struct _configEntry { ...@@ -48,7 +48,7 @@ typedef struct _configEntry {
List *configParamList; List *configParamList;
} ConfigEntry; } ConfigEntry;
static List *configEntriesList = NULL; static List *configEntriesList;
static ConfigParam *newConfigParam(char *value, int line) static ConfigParam *newConfigParam(char *value, int line)
{ {
...@@ -115,10 +115,8 @@ static void registerConfigParam(char *name, int repeatable, int block) ...@@ -115,10 +115,8 @@ static void registerConfigParam(char *name, int repeatable, int block)
{ {
ConfigEntry *entry; ConfigEntry *entry;
if (findInList(configEntriesList, name, NULL)) { if (findInList(configEntriesList, name, NULL))
ERROR("config parameter \"%s\" already registered\n", name); FATAL("config parameter \"%s\" already registered\n", name);
exit(EXIT_FAILURE);
}
entry = newConfigEntry(repeatable, block); entry = newConfigEntry(repeatable, block);
...@@ -146,6 +144,7 @@ void initConf(void) ...@@ -146,6 +144,7 @@ void initConf(void)
registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0); registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0);
registerConfigParam(CONF_PORT, 0, 0); registerConfigParam(CONF_PORT, 0, 0);
registerConfigParam(CONF_LOG_LEVEL, 0, 0); registerConfigParam(CONF_LOG_LEVEL, 0, 0);
registerConfigParam(CONF_ZEROCONF_NAME, 0, 0);
registerConfigParam(CONF_PASSWORD, 1, 0); registerConfigParam(CONF_PASSWORD, 1, 0);
registerConfigParam(CONF_DEFAULT_PERMS, 0, 0); registerConfigParam(CONF_DEFAULT_PERMS, 0, 0);
registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1); registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1);
...@@ -156,6 +155,7 @@ void initConf(void) ...@@ -156,6 +155,7 @@ void initConf(void)
registerConfigParam(CONF_REPLAYGAIN, 0, 0); registerConfigParam(CONF_REPLAYGAIN, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0); registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0); registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0);
registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0);
registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0); registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0); registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0); registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);
...@@ -173,6 +173,7 @@ void initConf(void) ...@@ -173,6 +173,7 @@ void initConf(void)
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0); registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
registerConfigParam(CONF_METADATA_TO_USE, 0, 0); registerConfigParam(CONF_METADATA_TO_USE, 0, 0);
registerConfigParam(CONF_SAVE_ABSOLUTE_PATHS, 0, 0); registerConfigParam(CONF_SAVE_ABSOLUTE_PATHS, 0, 0);
registerConfigParam(CONF_GAPLESS_MP3_PLAYBACK, 0, 0);
} }
static void addBlockParam(ConfigParam * param, char *name, char *value, static void addBlockParam(ConfigParam * param, char *name, char *value,
...@@ -222,19 +223,17 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string) ...@@ -222,19 +223,17 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
} }
if (2 != argsMinusComment) { if (2 != argsMinusComment) {
ERROR("improperly formatted config file at line %i:" FATAL("improperly formatted config file at line %i:"
" %s\n", *count, string); " %s\n", *count, string);
exit(EXIT_FAILURE);
} }
if (0 == strcmp(array[0], CONF_BLOCK_BEGIN) || if (0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[1], CONF_BLOCK_BEGIN) || 0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[0], CONF_BLOCK_END) || 0 == strcmp(array[0], CONF_BLOCK_END) ||
0 == strcmp(array[1], CONF_BLOCK_END)) { 0 == strcmp(array[1], CONF_BLOCK_END)) {
ERROR("improperly formatted config file at line %i:" FATAL("improperly formatted config file at line %i: %s\n"
" %s\n", *count, string); "in block beginning at line %i\n",
ERROR("in block beginning at line %i\n", ret->line); *count, string, ret->line);;
exit(EXIT_FAILURE);
} }
addBlockParam(ret, array[0], array[1], *count); addBlockParam(ret, array[0], array[1], *count);
...@@ -256,9 +255,8 @@ void readConf(char *file) ...@@ -256,9 +255,8 @@ void readConf(char *file)
ConfigParam *param; ConfigParam *param;
if (!(fp = fopen(file, "r"))) { if (!(fp = fopen(file, "r"))) {
ERROR("problems opening file %s for reading: %s\n", file, FATAL("problems opening file %s for reading: %s\n", file,
strerror(errno)); strerror(errno));
exit(EXIT_FAILURE);
} }
while (myFgets(string, MAX_STRING_SIZE, fp)) { while (myFgets(string, MAX_STRING_SIZE, fp)) {
...@@ -279,15 +277,13 @@ void readConf(char *file) ...@@ -279,15 +277,13 @@ void readConf(char *file)
} }
if (2 != argsMinusComment) { if (2 != argsMinusComment) {
ERROR("improperly formatted config file at line %i:" FATAL("improperly formatted config file at line %i:"
" %s\n", count, string); " %s\n", count, string);
exit(EXIT_FAILURE);
} }
if (!findInList(configEntriesList, array[0], &voidPtr)) { if (!findInList(configEntriesList, array[0], &voidPtr)) {
ERROR("unrecognized parameter in config file at line " FATAL("unrecognized parameter in config file at line "
"%i: %s\n", count, string); "%i: %s\n", count, string);
exit(EXIT_FAILURE);
} }
entry = (ConfigEntry *) voidPtr; entry = (ConfigEntry *) voidPtr;
...@@ -295,18 +291,15 @@ void readConf(char *file) ...@@ -295,18 +291,15 @@ void readConf(char *file)
if (!(entry->mask & CONF_REPEATABLE_MASK) && if (!(entry->mask & CONF_REPEATABLE_MASK) &&
entry->configParamList->numberOfNodes) { entry->configParamList->numberOfNodes) {
param = entry->configParamList->firstNode->data; param = entry->configParamList->firstNode->data;
ERROR FATAL("config parameter \"%s\" is first defined on line "
("config parameter \"%s\" is first defined on line "
"%i and redefined on line %i\n", array[0], "%i and redefined on line %i\n", array[0],
param->line, count); param->line, count);
exit(EXIT_FAILURE);
} }
if (entry->mask & CONF_BLOCK_MASK) { if (entry->mask & CONF_BLOCK_MASK) {
if (0 != strcmp(array[1], CONF_BLOCK_BEGIN)) { if (0 != strcmp(array[1], CONF_BLOCK_BEGIN)) {
ERROR("improperly formatted config file at " FATAL("improperly formatted config file at "
"line %i: %s\n", count, string); "line %i: %s\n", count, string);
exit(EXIT_FAILURE);
} }
param = readConfigBlock(fp, &count, string); param = readConfigBlock(fp, &count, string);
} else } else
...@@ -397,10 +390,8 @@ ConfigParam *parseConfigFilePath(char *name, int force) ...@@ -397,10 +390,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
ConfigParam *param = getConfigParam(name); ConfigParam *param = getConfigParam(name);
char *path; char *path;
if (!param && force) { if (!param && force)
ERROR("config parameter \"%s\" not found\n", name); FATAL("config parameter \"%s\" not found\n", name);
exit(EXIT_FAILURE);
}
if (!param) if (!param)
return NULL; return NULL;
...@@ -408,9 +399,8 @@ ConfigParam *parseConfigFilePath(char *name, int force) ...@@ -408,9 +399,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
path = param->value; path = param->value;
if (path[0] != '/' && path[0] != '~') { if (path[0] != '/' && path[0] != '~') {
ERROR("\"%s\" is not an absolute path at line %i\n", FATAL("\"%s\" is not an absolute path at line %i\n",
param->value, param->line); param->value, param->line);
exit(EXIT_FAILURE);
} }
/* Parse ~ in path */ /* Parse ~ in path */
else if (path[0] == '~') { else if (path[0] == '~') {
...@@ -423,17 +413,15 @@ ConfigParam *parseConfigFilePath(char *name, int force) ...@@ -423,17 +413,15 @@ ConfigParam *parseConfigFilePath(char *name, int force)
if (userParam) { if (userParam) {
pwd = getpwnam(userParam->value); pwd = getpwnam(userParam->value);
if (!pwd) { if (!pwd) {
ERROR("no such user %s at line %i\n", FATAL("no such user %s at line %i\n",
userParam->value, userParam->value,
userParam->line); userParam->line);
exit(EXIT_FAILURE);
} }
} else { } else {
uid_t uid = geteuid(); uid_t uid = geteuid();
if ((pwd = getpwuid(uid)) == NULL) { if ((pwd = getpwuid(uid)) == NULL) {
ERROR("problems getting passwd entry " FATAL("problems getting passwd entry "
"for current user\n"); "for current user\n");
exit(EXIT_FAILURE);
} }
} }
} else { } else {
...@@ -445,9 +433,8 @@ ConfigParam *parseConfigFilePath(char *name, int force) ...@@ -445,9 +433,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
*ch = '\0'; *ch = '\0';
pos += ch - path - 1; pos += ch - path - 1;
if ((pwd = getpwnam(path + 1)) == NULL) { if ((pwd = getpwnam(path + 1)) == NULL) {
ERROR("user \"%s\" not found at line %i\n", FATAL("user \"%s\" not found at line %i\n",
path + 1, param->line); path + 1, param->line);
exit(EXIT_FAILURE);
} }
if (foundSlash) if (foundSlash)
*ch = '/'; *ch = '/';
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -32,6 +32,7 @@ ...@@ -32,6 +32,7 @@
#define CONF_BIND_TO_ADDRESS "bind_to_address" #define CONF_BIND_TO_ADDRESS "bind_to_address"
#define CONF_PORT "port" #define CONF_PORT "port"
#define CONF_LOG_LEVEL "log_level" #define CONF_LOG_LEVEL "log_level"
#define CONF_ZEROCONF_NAME "zeroconf_name"
#define CONF_PASSWORD "password" #define CONF_PASSWORD "password"
#define CONF_DEFAULT_PERMS "default_permissions" #define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_AUDIO_OUTPUT "audio_output" #define CONF_AUDIO_OUTPUT "audio_output"
...@@ -42,6 +43,7 @@ ...@@ -42,6 +43,7 @@
#define CONF_REPLAYGAIN "replaygain" #define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp" #define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_VOLUME_NORMALIZATION "volume_normalization" #define CONF_VOLUME_NORMALIZATION "volume_normalization"
#define CONF_SAMPLERATE_CONVERTER "samplerate_converter"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size" #define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play" #define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size" #define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
...@@ -59,6 +61,7 @@ ...@@ -59,6 +61,7 @@
#define CONF_ID3V1_ENCODING "id3v1_encoding" #define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_METADATA_TO_USE "metadata_to_use" #define CONF_METADATA_TO_USE "metadata_to_use"
#define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists" #define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
#define CONF_GAPLESS_MP3_PLAYBACK "gapless_mp3_playback"
typedef struct _BlockParam { typedef struct _BlockParam {
char *name; char *name;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -22,14 +22,11 @@ ...@@ -22,14 +22,11 @@
#include "myfprintf.h" #include "myfprintf.h"
#include "utils.h" #include "utils.h"
#include "playlist.h" #include "playlist.h"
#include "song.h"
#include "tag.h" #include "tag.h"
#include "tagTracker.h" #include "tagTracker.h"
#include "log.h" #include "log.h"
#include "storedPlaylist.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 { typedef struct _ListCommandItem {
mpd_sint8 tagType; mpd_sint8 tagType;
...@@ -42,97 +39,11 @@ typedef struct _LocateTagItemArray { ...@@ -42,97 +39,11 @@ typedef struct _LocateTagItemArray {
LocateTagItem *items; LocateTagItem *items;
} LocateTagItemArray; } LocateTagItemArray;
int getLocateTagItemType(char *str) typedef struct _SearchStats {
{ LocateTagItemArray locateArray;
int i; int numberOfSongs;
unsigned long playTime;
if (0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) { } SearchStats;
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 = xstrdup(needle);
return 0;
}
LocateTagItem *newLocateTagItem(char *typeStr, char *needle)
{
LocateTagItem *ret = xmalloc(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 = xmalloc(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) static int countSongsInDirectory(int fd, Directory * directory, void *data)
{ {
...@@ -158,53 +69,12 @@ static int printSongInDirectory(int fd, Song * song, void *data) ...@@ -158,53 +69,12 @@ static int printSongInDirectory(int fd, Song * song, void *data)
return 0; 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) static int searchInDirectory(int fd, Song * song, void *data)
{ {
LocateTagItemArray *array = data; LocateTagItemArray *array = data;
int i;
for (i = 0; i < array->numItems; i++) { if (strstrSearchTags(song, array->numItems, array->items))
if (!strstrSearchTag(song, array->items[i].tagType, printSongInfo(fd, song);
array->items[i].needle)) {
return 0;
}
}
printSongInfo(fd, song);
return 0; return 0;
} }
...@@ -237,54 +107,62 @@ int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items) ...@@ -237,54 +107,62 @@ int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
return ret; return ret;
} }
static int tagItemFoundAndMatches(Song * song, int type, char *str) static int findInDirectory(int fd, Song * song, void *data)
{ {
int i; LocateTagItemArray *array = data;
if (type == LOCATE_TAG_FILE_TYPE) { if (tagItemsFoundAndMatches(song, array->numItems, array->items))
if (0 == strcmp(str, getSongUrl(song))) printSongInfo(fd, song);
return 1;
}
if (!song->tag) return 0;
return 0; }
for (i = 0; i < song->tag->numOfItems; i++) { int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
if (song->tag->items[i].type != type) {
continue; LocateTagItemArray array;
if (0 == strcmp(str, song->tag->items[i].value)) array.numItems = numItems;
return 1; array.items = items;
}
return 0; return traverseAllIn(fd, name, findInDirectory, NULL, (void *)&array);
} }
static int findInDirectory(int fd, Song * song, void *data) static void printSearchStats(int fd, SearchStats *stats)
{ {
LocateTagItemArray *array = data; fdprintf(fd, "songs: %i\n", stats->numberOfSongs);
int i; fdprintf(fd, "playtime: %li\n", stats->playTime);
}
for (i = 0; i < array->numItems; i++) { static int searchStatsInDirectory(int fd, Song * song, void *data)
if (!tagItemFoundAndMatches(song, array->items[i].tagType, {
array->items[i].needle)) { SearchStats *stats = data;
return 0;
}
}
printSongInfo(fd, song); if (tagItemsFoundAndMatches(song, stats->locateArray.numItems,
stats->locateArray.items)) {
stats->numberOfSongs++;
if (song->tag->time > 0)
stats->playTime += song->tag->time;
}
return 0; return 0;
} }
int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items) int searchStatsForSongsIn(int fd, char *name, int numItems,
LocateTagItem * items)
{ {
LocateTagItemArray array; SearchStats stats;
int ret;
array.numItems = numItems; stats.locateArray.numItems = numItems;
array.items = items; stats.locateArray.items = items;
stats.numberOfSongs = 0;
stats.playTime = 0;
return traverseAllIn(fd, name, findInDirectory, NULL, (void *)&array); ret = traverseAllIn(fd, name, searchStatsInDirectory, NULL, &stats);
if (ret == 0)
printSearchStats(fd, &stats);
return ret;
} }
int printAllIn(int fd, char *name) int printAllIn(int fd, char *name)
...@@ -298,11 +176,24 @@ static int directoryAddSongToPlaylist(int fd, Song * song, void *data) ...@@ -298,11 +176,24 @@ static int directoryAddSongToPlaylist(int fd, Song * song, void *data)
return addSongToPlaylist(fd, song, 0); return addSongToPlaylist(fd, song, 0);
} }
static int directoryAddSongToStoredPlaylist(int fd, Song *song, void *data)
{
if (appendSongToStoredPlaylistByPath(fd, (char *)data, song) != 0)
return -1;
return 0;
}
int addAllIn(int fd, char *name) int addAllIn(int fd, char *name)
{ {
return traverseAllIn(fd, name, directoryAddSongToPlaylist, NULL, NULL); return traverseAllIn(fd, name, directoryAddSongToPlaylist, NULL, NULL);
} }
int addAllInToStoredPlaylist(int fd, char *name, char *utf8file)
{
return traverseAllIn(fd, name, directoryAddSongToStoredPlaylist, NULL,
(void *)utf8file);
}
static int directoryPrintSongInfo(int fd, Song * song, void *data) static int directoryPrintSongInfo(int fd, Song * song, void *data)
{ {
return printSongInfo(fd, song); return printSongInfo(fd, song);
...@@ -384,17 +275,12 @@ static void visitTag(int fd, Song * song, int tagType) ...@@ -384,17 +275,12 @@ static void visitTag(int fd, Song * song, int tagType)
static int listUniqueTagsInDirectory(int fd, Song * song, void *data) static int listUniqueTagsInDirectory(int fd, Song * song, void *data)
{ {
ListCommandItem *item = data; ListCommandItem *item = data;
int i;
for (i = 0; i < item->numConditionals; i++) { if (tagItemsFoundAndMatches(song, item->numConditionals,
if (!tagItemFoundAndMatches(song, item->conditionals[i].tagType, item->conditionals)) {
item->conditionals[i].needle)) { visitTag(fd, song, item->tagType);
return 0;
}
} }
visitTag(fd, song, item->tagType);
return 0; return 0;
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -21,39 +21,24 @@ ...@@ -21,39 +21,24 @@
#include <stdio.h> #include <stdio.h>
#include "tag.h" #include "locate.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 printAllIn(int fd, char *name);
int addAllIn(int fd, char *name); int addAllIn(int fd, char *name);
int addAllInToStoredPlaylist(int fd, char *name, char *utf8file);
int printInfoForAllIn(int fd, char *name); int printInfoForAllIn(int fd, char *name);
int searchForSongsIn(int fd, char *name, int numItems, int searchForSongsIn(int fd, char *name, int numItems,
LocateTagItem * items); LocateTagItem * items);
int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items); int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items);
int searchStatsForSongsIn(int fd, char *name, int numItems,
LocateTagItem * items);
int countSongsIn(int fd, char *name); int countSongsIn(int fd, char *name);
unsigned long sumSongTimesIn(int fd, char *name); unsigned long sumSongTimesIn(int fd, char *name);
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
#include <unistd.h> #include <unistd.h>
#include <string.h> #include <string.h>
static int decode_pid = 0; static int decode_pid;
void decodeSigHandler(int sig, siginfo_t * si, void *v) void decodeSigHandler(int sig, siginfo_t * si, void *v)
{ {
...@@ -76,7 +76,6 @@ static void stopDecode(DecoderControl * dc) ...@@ -76,7 +76,6 @@ static void stopDecode(DecoderControl * dc)
static void quitDecode(PlayerControl * pc, DecoderControl * dc) static void quitDecode(PlayerControl * pc, DecoderControl * dc)
{ {
stopDecode(dc); stopDecode(dc);
pc->metadataState = PLAYER_METADATA_STATE_READ;
pc->state = PLAYER_STATE_STOP; pc->state = PLAYER_STATE_STOP;
dc->seek = 0; dc->seek = 0;
pc->play = 0; pc->play = 0;
...@@ -221,20 +220,20 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc, ...@@ -221,20 +220,20 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc,
} \ } \
if(pc->pause) { \ if(pc->pause) { \
pause = !pause; \ pause = !pause; \
if(pause) pc->state = PLAYER_STATE_PAUSE; \ if (pause) pc->state = PLAYER_STATE_PAUSE; \
else { \ else { \
if(openAudioDevice(NULL)<0) { \ if (openAudioDevice(NULL) >= 0) pc->state = PLAYER_STATE_PLAY; \
else { \
pathcpy_trunc(pc->erroredUrl, pc->utf8url); \ pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
pc->error = PLAYER_ERROR_AUDIO; \ pc->error = PLAYER_ERROR_AUDIO; \
ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \ ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
quitDecode(pc,dc); \ pause = -1; \
return; \
} \ } \
pc->state = PLAYER_STATE_PLAY; \
} \ } \
pc->pause = 0; \ pc->pause = 0; \
kill(getppid(),SIGUSR1); \ kill(getppid(), SIGUSR1); \
if(pause) { \ if (pause == -1) pause = 1; \
else if (pause) { \
dropBufferedAudio(); \ dropBufferedAudio(); \
closeAudioDevice(); \ closeAudioDevice(); \
} \ } \
...@@ -285,7 +284,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, ...@@ -285,7 +284,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
return; return;
} }
dc->seekable = inStream.seekable;
dc->state = DECODE_STATE_START; dc->state = DECODE_STATE_START;
dc->start = 0; dc->start = 0;
...@@ -295,6 +293,9 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb, ...@@ -295,6 +293,9 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
my_usleep(1000); my_usleep(1000);
} }
/* for http streams, seekable is determined in bufferInputStream */
dc->seekable = inStream.seekable;
if (dc->stop) { if (dc->stop) {
dc->state = DECODE_STATE_STOP; dc->state = DECODE_STATE_STOP;
dc->stop = 0; dc->stop = 0;
...@@ -480,10 +481,10 @@ static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc, ...@@ -480,10 +481,10 @@ static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
while (cb->begin != to) { while (cb->begin != to) {
handleMetadata(cb, pc, previous, currentChunkSent, handleMetadata(cb, pc, previous, currentChunkSent,
currentChunk); currentChunk);
cb->begin++; if (cb->begin + 1 >= buffered_chunks) {
if (cb->begin >= buffered_chunks) {
cb->begin = 0; cb->begin = 0;
} }
else cb->begin++;
} }
} }
...@@ -516,7 +517,8 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * ...@@ -516,7 +517,8 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
pc->play = 0; pc->play = 0;
kill(getppid(), SIGUSR1); kill(getppid(), SIGUSR1);
while (decode_pid > 0 && cb->end - cb->begin < bbp && while (decode_pid > 0 &&
cb->end - cb->begin < bbp &&
cb->end != buffered_chunks - 1 && cb->end != buffered_chunks - 1 &&
dc->state != DECODE_STATE_STOP) { dc->state != DECODE_STATE_STOP) {
processDecodeInput(); processDecodeInput();
...@@ -617,10 +619,10 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * ...@@ -617,10 +619,10 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
cb->begin = 0; cb->begin = 0;
} else } else
cb->begin++; cb->begin++;
} else if (next == cb->begin) { } else if (cb->begin != end && cb->begin == next) {
if (doCrossFade == 1 && nextChunk >= 0) { if (doCrossFade == 1 && nextChunk >= 0) {
nextChunk = cb->begin + crossFadeChunks; nextChunk = cb->begin + crossFadeChunks;
test = cb->end; test = end;
if (end < cb->begin) if (end < cb->begin)
test += buffered_chunks; test += buffered_chunks;
if (nextChunk < test) { if (nextChunk < test) {
...@@ -663,6 +665,7 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer * ...@@ -663,6 +665,7 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
quit = 1; quit = 1;
break; break;
} else { } else {
/*DEBUG("waiting for decoded audio, play silence\n");*/
if (playAudio(silence, CHUNK_SIZE) < 0) if (playAudio(silence, CHUNK_SIZE) < 0)
quit = 1; quit = 1;
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -59,15 +59,15 @@ ...@@ -59,15 +59,15 @@
#define DIRECTORY_RETURN_UPDATE 1 #define DIRECTORY_RETURN_UPDATE 1
#define DIRECTORY_RETURN_ERROR -1 #define DIRECTORY_RETURN_ERROR -1
Directory *mp3rootDirectory = NULL; static Directory *mp3rootDirectory;
time_t directory_dbModTime = 0; static time_t directory_dbModTime;
volatile int directory_updatePid = 0; static volatile int directory_updatePid;
volatile int directory_reReadDB = 0; static volatile int directory_reReadDB;
volatile mpd_uint16 directory_updateJobId = 0; static volatile mpd_uint16 directory_updateJobId;
static DirectoryList *newDirectoryList(); static DirectoryList *newDirectoryList();
...@@ -543,7 +543,7 @@ static int updatePath(char *utf8path) ...@@ -543,7 +543,7 @@ static int updatePath(char *utf8path)
free(path); free(path);
return 0; return 0;
} }
/* if updateDirectory fials, means we should delete it */ /* if updateDirectory fails, means we should delete it */
else { else {
LOG("removing directory: %s\n", path); LOG("removing directory: %s\n", path);
deleteFromList(parentDirectory->subDirectories, deleteFromList(parentDirectory->subDirectories,
...@@ -573,7 +573,7 @@ static int updatePath(char *utf8path) ...@@ -573,7 +573,7 @@ static int updatePath(char *utf8path)
return 1; return 1;
} }
} }
/* if updateDirectory fials, means we should delete it */ /* if updateDirectory fails, means we should delete it */
else { else {
removeSongFromDirectory(parentDirectory, shortname); removeSongFromDirectory(parentDirectory, shortname);
ret = 1; ret = 1;
...@@ -835,13 +835,21 @@ static Directory *findSubDirectory(Directory * directory, char *name) ...@@ -835,13 +835,21 @@ static Directory *findSubDirectory(Directory * directory, char *name)
return NULL; return NULL;
} }
int isRootDirectory(char *name)
{
if (name == NULL || name[0] == '\0' || strcmp(name, "/") == 0) {
return 1;
}
return 0;
}
static Directory *getSubDirectory(Directory * directory, char *name, static Directory *getSubDirectory(Directory * directory, char *name,
char **shortname) char **shortname)
{ {
Directory *subDirectory; Directory *subDirectory;
int len; int len;
if (name == NULL || name[0] == '\0' || strcmp(name, "/") == 0) { if (isRootDirectory(name)) {
return directory; return directory;
} }
...@@ -943,23 +951,18 @@ static void readDirectoryInfo(FILE * fp, Directory * directory) ...@@ -943,23 +951,18 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
&& 0 != strncmp(DIRECTORY_END, buffer, strlen(DIRECTORY_END))) { && 0 != strncmp(DIRECTORY_END, buffer, strlen(DIRECTORY_END))) {
if (0 == strncmp(DIRECTORY_DIR, buffer, strlen(DIRECTORY_DIR))) { if (0 == strncmp(DIRECTORY_DIR, buffer, strlen(DIRECTORY_DIR))) {
key = xstrdup(&(buffer[strlen(DIRECTORY_DIR)])); key = xstrdup(&(buffer[strlen(DIRECTORY_DIR)]));
if (!myFgets(buffer, bufferSize, fp)) { if (!myFgets(buffer, bufferSize, fp))
ERROR("Error reading db, fgets\n"); FATAL("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
/* for compatibility with db's prior to 0.11 */ /* for compatibility with db's prior to 0.11 */
if (0 == strncmp(DIRECTORY_MTIME, buffer, if (0 == strncmp(DIRECTORY_MTIME, buffer,
strlen(DIRECTORY_MTIME))) { strlen(DIRECTORY_MTIME))) {
if (!myFgets(buffer, bufferSize, fp)) { if (!myFgets(buffer, bufferSize, fp))
ERROR("Error reading db, fgets\n"); FATAL("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
} }
if (strncmp if (strncmp
(DIRECTORY_BEGIN, buffer, (DIRECTORY_BEGIN, buffer,
strlen(DIRECTORY_BEGIN))) { strlen(DIRECTORY_BEGIN))) {
ERROR("Error reading db at line: %s\n", buffer); FATAL("Error reading db at line: %s\n", buffer);
exit(EXIT_FAILURE);
} }
name = xstrdup(&(buffer[strlen(DIRECTORY_BEGIN)])); name = xstrdup(&(buffer[strlen(DIRECTORY_BEGIN)]));
...@@ -993,8 +996,7 @@ static void readDirectoryInfo(FILE * fp, Directory * directory) ...@@ -993,8 +996,7 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
} else if (0 == strncmp(SONG_BEGIN, buffer, strlen(SONG_BEGIN))) { } else if (0 == strncmp(SONG_BEGIN, buffer, strlen(SONG_BEGIN))) {
readSongInfoIntoList(fp, directory->songs, directory); readSongInfoIntoList(fp, directory->songs, directory);
} else { } else {
ERROR("Unknown line in db: %s\n", buffer); FATAL("Unknown line in db: %s\n", buffer);
exit(EXIT_FAILURE);
} }
} }
...@@ -1091,6 +1093,7 @@ int writeDirectoryDB(void) ...@@ -1091,6 +1093,7 @@ int writeDirectoryDB(void)
{ {
FILE *fp; FILE *fp;
char *dbFile = getDbFile(); char *dbFile = getDbFile();
struct stat st;
DEBUG("removing empty directories from DB\n"); DEBUG("removing empty directories from DB\n");
deleteEmptyDirectoriesInDirectory(mp3rootDirectory); deleteEmptyDirectoriesInDirectory(mp3rootDirectory);
...@@ -1101,7 +1104,7 @@ int writeDirectoryDB(void) ...@@ -1101,7 +1104,7 @@ int writeDirectoryDB(void)
DEBUG("writing DB\n"); DEBUG("writing DB\n");
while (!(fp = fopen(dbFile, "w")) && errno == EINTR) ; while (!(fp = fopen(dbFile, "w")) && errno == EINTR);
if (!fp) { if (!fp) {
ERROR("unable to write to db file \"%s\": %s\n", ERROR("unable to write to db file \"%s\": %s\n",
dbFile, strerror(errno)); dbFile, strerror(errno));
...@@ -1116,7 +1119,10 @@ int writeDirectoryDB(void) ...@@ -1116,7 +1119,10 @@ int writeDirectoryDB(void)
writeDirectoryInfo(fp, mp3rootDirectory); writeDirectoryInfo(fp, mp3rootDirectory);
while (fclose(fp) && errno == EINTR) ; while (fclose(fp) && errno == EINTR);
if (stat(dbFile, &st) == 0)
directory_dbModTime = st.st_mtime;
return 0; return 0;
} }
...@@ -1131,7 +1137,7 @@ int readDirectoryDB(void) ...@@ -1131,7 +1137,7 @@ int readDirectoryDB(void)
mp3rootDirectory = newDirectory(NULL, NULL); mp3rootDirectory = newDirectory(NULL, NULL);
while (!(fp = fopen(dbFile, "r")) && errno == EINTR) ; while (!(fp = fopen(dbFile, "r")) && errno == EINTR) ;
if (fp == NULL) { if (fp == NULL) {
ERROR("unable open db file \"%s\": %s\n", ERROR("unable to open db file \"%s\": %s\n",
dbFile, strerror(errno)); dbFile, strerror(errno));
return -1; return -1;
} }
...@@ -1143,21 +1149,16 @@ int readDirectoryDB(void) ...@@ -1143,21 +1149,16 @@ int readDirectoryDB(void)
int foundFsCharset = 0; int foundFsCharset = 0;
int foundVersion = 0; int foundVersion = 0;
if (!myFgets(buffer, bufferSize, fp)) { if (!myFgets(buffer, bufferSize, fp))
ERROR("Error reading db, fgets\n"); FATAL("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
if (0 == strcmp(DIRECTORY_INFO_BEGIN, buffer)) { if (0 == strcmp(DIRECTORY_INFO_BEGIN, buffer)) {
while (myFgets(buffer, bufferSize, fp) && while (myFgets(buffer, bufferSize, fp) &&
0 != strcmp(DIRECTORY_INFO_END, buffer)) { 0 != strcmp(DIRECTORY_INFO_END, buffer)) {
if (0 == strncmp(DIRECTORY_MPD_VERSION, buffer, if (0 == strncmp(DIRECTORY_MPD_VERSION, buffer,
strlen(DIRECTORY_MPD_VERSION))) strlen(DIRECTORY_MPD_VERSION)))
{ {
if (foundVersion) { if (foundVersion)
ERROR("already found " FATAL("already found version in db\n");
"version in db\n");
exit(EXIT_FAILURE);
}
foundVersion = 1; foundVersion = 1;
} else if (0 == } else if (0 ==
strncmp(DIRECTORY_FS_CHARSET, buffer, strncmp(DIRECTORY_FS_CHARSET, buffer,
...@@ -1166,20 +1167,13 @@ int readDirectoryDB(void) ...@@ -1166,20 +1167,13 @@ int readDirectoryDB(void)
char *fsCharset; char *fsCharset;
char *tempCharset; char *tempCharset;
if (foundFsCharset) { if (foundFsCharset)
WARNING("already found " FATAL("already found fs charset in db\n");
"fs charset in db\n");
exit(EXIT_FAILURE);
}
foundFsCharset = 1; foundFsCharset = 1;
fsCharset = fsCharset = &(buffer[strlen(DIRECTORY_FS_CHARSET)]);
&(buffer if ((tempCharset = getConfigParamValue(CONF_FS_CHARSET))
[strlen(DIRECTORY_FS_CHARSET)]);
if ((tempCharset =
getConfigParamValue
(CONF_FS_CHARSET))
&& strcmp(fsCharset, tempCharset)) { && strcmp(fsCharset, tempCharset)) {
WARNING("Using \"%s\" for the " WARNING("Using \"%s\" for the "
"filesystem charset " "filesystem charset "
...@@ -1190,10 +1184,8 @@ int readDirectoryDB(void) ...@@ -1190,10 +1184,8 @@ int readDirectoryDB(void)
setFsCharset(fsCharset); setFsCharset(fsCharset);
} }
} else { } else {
ERROR FATAL("directory: unknown line in db info: %s\n",
("directory: unknown line in db info: %s\n",
buffer); buffer);
exit(EXIT_FAILURE);
} }
} }
} else { } else {
...@@ -1225,14 +1217,12 @@ void updateMp3Directory(void) ...@@ -1225,14 +1217,12 @@ void updateMp3Directory(void)
/* nothing updated */ /* nothing updated */
return; return;
case 1: case 1:
if (writeDirectoryDB() < 0) { if (writeDirectoryDB() < 0)
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
}
break; break;
default: default:
/* something was updated and db should be written */ /* something was updated and db should be written */
ERROR("problems updating music db\n"); FATAL("problems updating music db\n");
exit(EXIT_FAILURE);
} }
return; return;
...@@ -1311,16 +1301,11 @@ static void freeAllDirectoryStats(Directory * directory) ...@@ -1311,16 +1301,11 @@ static void freeAllDirectoryStats(Directory * directory)
void initMp3Directory(void) void initMp3Directory(void)
{ {
struct stat st;
mp3rootDirectory = newDirectory(NULL, NULL); mp3rootDirectory = newDirectory(NULL, NULL);
exploreDirectory(mp3rootDirectory); exploreDirectory(mp3rootDirectory);
freeAllDirectoryStats(mp3rootDirectory); freeAllDirectoryStats(mp3rootDirectory);
stats.numberOfSongs = countSongsIn(STDERR_FILENO, NULL); stats.numberOfSongs = countSongsIn(STDERR_FILENO, NULL);
stats.dbPlayTime = sumSongTimesIn(STDERR_FILENO, NULL); stats.dbPlayTime = sumSongTimesIn(STDERR_FILENO, NULL);
if (stat(getDbFile(), &st) == 0)
directory_dbModTime = st.st_mtime;
} }
static Song *getSongDetails(char *file, char **shortnameRet, static Song *getSongDetails(char *file, char **shortnameRet,
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -51,6 +51,8 @@ void initMp3Directory(void); ...@@ -51,6 +51,8 @@ void initMp3Directory(void);
void closeMp3Directory(void); void closeMp3Directory(void);
int isRootDirectory(char *name);
int printDirectoryInfo(int fd, char *dirname); int printDirectoryInfo(int fd, char *dirname);
int checkDirectoryDB(void); int checkDirectoryDB(void);
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -24,7 +24,7 @@ ...@@ -24,7 +24,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
static List *inputPlugin_list = NULL; static List *inputPlugin_list;
void loadInputPlugin(InputPlugin * inputPlugin) void loadInputPlugin(InputPlugin * inputPlugin)
{ {
...@@ -59,7 +59,7 @@ static int stringFoundInStringArray(char **array, char *suffix) ...@@ -59,7 +59,7 @@ static int stringFoundInStringArray(char **array, char *suffix)
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next) InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
{ {
static ListNode *pos = NULL; static ListNode *pos;
ListNode *node; ListNode *node;
InputPlugin *plugin; InputPlugin *plugin;
...@@ -88,7 +88,7 @@ InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next) ...@@ -88,7 +88,7 @@ InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next) InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next)
{ {
static ListNode *pos = NULL; static ListNode *pos;
ListNode *node; ListNode *node;
InputPlugin *plugin; InputPlugin *plugin;
...@@ -137,16 +137,6 @@ void printAllInputPluginSuffixes(FILE * fp) ...@@ -137,16 +137,6 @@ void printAllInputPluginSuffixes(FILE * fp)
fflush(fp); fflush(fp);
} }
extern InputPlugin mp3Plugin;
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(void) void initInputPlugins(void)
{ {
inputPlugin_list = makeList(NULL, 1); inputPlugin_list = makeList(NULL, 1);
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -96,4 +96,14 @@ void initInputPlugins(void); ...@@ -96,4 +96,14 @@ void initInputPlugins(void);
/* this is where we "unload" all the "plugins" */ /* this is where we "unload" all the "plugins" */
void finishInputPlugins(void); void finishInputPlugins(void);
extern InputPlugin mp3Plugin;
extern InputPlugin oggvorbisPlugin;
extern InputPlugin flacPlugin;
extern InputPlugin oggflacPlugin;
extern InputPlugin audiofilePlugin;
extern InputPlugin mp4Plugin;
extern InputPlugin mpcPlugin;
extern InputPlugin aacPlugin;
extern InputPlugin modPlugin;
#endif #endif
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Common data structures and functions used by FLAC and OggFLAC * Common data structures and functions used by FLAC and OggFLAC
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Common data structures and functions used by FLAC and OggFLAC * Common data structures and functions used by FLAC and OggFLAC
...@@ -30,7 +30,116 @@ ...@@ -30,7 +30,116 @@
#include "../inputStream.h" #include "../inputStream.h"
#include "../outputBuffer.h" #include "../outputBuffer.h"
#include "../decode.h" #include "../decode.h"
#include <FLAC/seekable_stream_decoder.h> #include <FLAC/export.h>
#if !defined(FLAC_API_VERSION_CURRENT) || FLAC_API_VERSION_CURRENT <= 7
# include <FLAC/seekable_stream_decoder.h>
# define flac_decoder FLAC__SeekableStreamDecoder
# define flac_new() FLAC__seekable_stream_decoder_new()
# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) (0)
# define flac_get_decode_position(x,y) \
FLAC__seekable_stream_decoder_get_decode_position(x,y)
# define flac_get_state(x) FLAC__seekable_stream_decoder_get_state(x)
# define flac_process_single(x) FLAC__seekable_stream_decoder_process_single(x)
# define flac_process_metadata(x) \
FLAC__seekable_stream_decoder_process_until_end_of_metadata(x)
# define flac_seek_absolute(x,y) \
FLAC__seekable_stream_decoder_seek_absolute(x,y)
# define flac_finish(x) FLAC__seekable_stream_decoder_finish(x)
# define flac_delete(x) FLAC__seekable_stream_decoder_delete(x)
# define flac_decoder_eof FLAC__SEEKABLE_STREAM_DECODER_END_OF_STREAM
typedef unsigned flac_read_status_size_t;
# define flac_read_status FLAC__SeekableStreamDecoderReadStatus
# define flac_read_status_continue \
FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK
# define flac_read_status_eof FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_OK
# define flac_read_status_abort \
FLAC__SEEKABLE_STREAM_DECODER_READ_STATUS_ERROR
# define flac_seek_status FLAC__SeekableStreamDecoderSeekStatus
# define flac_seek_status_ok FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_OK
# define flac_seek_status_error FLAC__SEEKABLE_STREAM_DECODER_SEEK_STATUS_ERROR
# define flac_tell_status FLAC__SeekableStreamDecoderTellStatus
# define flac_tell_status_ok FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_OK
# define flac_tell_status_error \
FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
# define flac_tell_status_unsupported \
FLAC__SEEKABLE_STREAM_DECODER_TELL_STATUS_ERROR
# define flac_length_status FLAC__SeekableStreamDecoderLengthStatus
# define flac_length_status_ok FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_OK
# define flac_length_status_error \
FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
# define flac_length_status_unsupported \
FLAC__SEEKABLE_STREAM_DECODER_LENGTH_STATUS_ERROR
# ifdef HAVE_OGGFLAC
# include <OggFLAC/seekable_stream_decoder.h>
# endif
#else /* FLAC_API_VERSION_CURRENT >= 7 */
/* OggFLAC support is handled by our flac_plugin already, and
* thus we *can* always have it if libFLAC was compiled with it */
# ifndef HAVE_OGGFLAC
# define HAVE_OGGFLAC 1
# endif
# include "_ogg_common.h"
# undef HAVE_OGGFLAC /* we don't need this defined anymore */
# include <FLAC/stream_decoder.h>
# define flac_decoder FLAC__StreamDecoder
# define flac_new() FLAC__stream_decoder_new()
# define flac_init(a,b,c,d,e,f,g,h,i,j) \
(FLAC__stream_decoder_init_stream(a,b,c,d,e,f,g,h,i,j) \
== FLAC__STREAM_DECODER_INIT_STATUS_OK)
# define flac_ogg_init(a,b,c,d,e,f,g,h,i,j) \
(FLAC__stream_decoder_init_ogg_stream(a,b,c,d,e,f,g,h,i,j) \
== FLAC__STREAM_DECODER_INIT_STATUS_OK)
# define flac_get_decode_position(x,y) \
FLAC__stream_decoder_get_decode_position(x,y)
# define flac_get_state(x) FLAC__stream_decoder_get_state(x)
# define flac_process_single(x) FLAC__stream_decoder_process_single(x)
# define flac_process_metadata(x) \
FLAC__stream_decoder_process_until_end_of_metadata(x)
# define flac_seek_absolute(x,y) FLAC__stream_decoder_seek_absolute(x,y)
# define flac_finish(x) FLAC__stream_decoder_finish(x)
# define flac_delete(x) FLAC__stream_decoder_delete(x)
# define flac_decoder_eof FLAC__STREAM_DECODER_END_OF_STREAM
typedef size_t flac_read_status_size_t;
# define flac_read_status FLAC__StreamDecoderReadStatus
# define flac_read_status_continue \
FLAC__STREAM_DECODER_READ_STATUS_CONTINUE
# define flac_read_status_eof FLAC__STREAM_DECODER_READ_STATUS_END_OF_STREAM
# define flac_read_status_abort FLAC__STREAM_DECODER_READ_STATUS_ABORT
# define flac_seek_status FLAC__StreamDecoderSeekStatus
# define flac_seek_status_ok FLAC__STREAM_DECODER_SEEK_STATUS_OK
# define flac_seek_status_error FLAC__STREAM_DECODER_SEEK_STATUS_ERROR
# define flac_seek_status_unsupported \
FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED
# define flac_tell_status FLAC__StreamDecoderTellStatus
# define flac_tell_status_ok FLAC__STREAM_DECODER_TELL_STATUS_OK
# define flac_tell_status_error FLAC__STREAM_DECODER_TELL_STATUS_ERROR
# define flac_tell_status_unsupported \
FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED
# define flac_length_status FLAC__StreamDecoderLengthStatus
# define flac_length_status_ok FLAC__STREAM_DECODER_LENGTH_STATUS_OK
# define flac_length_status_error FLAC__STREAM_DECODER_LENGTH_STATUS_ERROR
# define flac_length_status_unsupported \
FLAC__STREAM_DECODER_LENGTH_STATUS_UNSUPPORTED
#endif /* FLAC_API_VERSION_CURRENT >= 7 */
#include <FLAC/metadata.h> #include <FLAC/metadata.h>
#define FLAC_CHUNK_SIZE 4080 #define FLAC_CHUNK_SIZE 4080
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC) * Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC) * Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -237,7 +237,7 @@ static float getAacFloatTotalTime(char *file) ...@@ -237,7 +237,7 @@ static float getAacFloatTotalTime(char *file)
size_t fileread, tagsize; size_t fileread, tagsize;
faacDecHandle decoder; faacDecHandle decoder;
faacDecConfigurationPtr config; faacDecConfigurationPtr config;
unsigned int sampleRate; unsigned long sampleRate;
unsigned char channels; unsigned char channels;
InputStream inStream; InputStream inStream;
long bread; long bread;
...@@ -293,7 +293,7 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path) ...@@ -293,7 +293,7 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
faacDecFrameInfo frameInfo; faacDecFrameInfo frameInfo;
faacDecConfigurationPtr config; faacDecConfigurationPtr config;
long bread; long bread;
unsigned int sampleRate; unsigned long sampleRate;
unsigned char channels; unsigned char channels;
int eof = 0; int eof = 0;
unsigned int sampleCount; unsigned int sampleCount;
...@@ -470,17 +470,6 @@ InputPlugin aacPlugin = { ...@@ -470,17 +470,6 @@ InputPlugin aacPlugin = {
#else #else
InputPlugin aacPlugin = { InputPlugin aacPlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
#endif /* HAVE_FAAD */ #endif /* HAVE_FAAD */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net> * libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
...@@ -183,17 +183,6 @@ InputPlugin audiofilePlugin = { ...@@ -183,17 +183,6 @@ InputPlugin audiofilePlugin = {
#else #else
InputPlugin audiofilePlugin = { InputPlugin audiofilePlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_AUDIOFILE */ #endif /* HAVE_AUDIOFILE */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -64,8 +64,13 @@ static MDRIVER drv_mpd = { ...@@ -64,8 +64,13 @@ static MDRIVER drv_mpd = {
"MPD Output Driver v0.1", "MPD Output Driver v0.1",
0, 0,
255, 255,
"mpd", #if (LIBMIKMOD_VERSION > 0x030106)
NULL, "mpd", /* Alias */
#if (LIBMIKMOD_VERSION > 0x030200)
NULL, /* CmdLineHelp */
#endif
NULL, /* CommandLine */
#endif
mod_mpd_IsThere, mod_mpd_IsThere,
VC_SampleLoad, VC_SampleLoad,
VC_SampleUnload, VC_SampleUnload,
...@@ -92,8 +97,8 @@ static MDRIVER drv_mpd = { ...@@ -92,8 +97,8 @@ static MDRIVER drv_mpd = {
VC_VoiceRealVolume VC_VoiceRealVolume
}; };
static int mod_mikModInitiated = 0; static int mod_mikModInitiated;
static int mod_mikModInitError = 0; static int mod_mikModInitError;
static int mod_initMikMod(void) static int mod_initMikMod(void)
{ {
...@@ -143,6 +148,9 @@ static mod_Data *mod_open(char *path) ...@@ -143,6 +148,9 @@ static mod_Data *mod_open(char *path)
if (!(moduleHandle = Player_Load(path, 128, 0))) if (!(moduleHandle = Player_Load(path, 128, 0)))
return NULL; return NULL;
/* Prevent module from looping forever */
moduleHandle->loop = 0;
data = xmalloc(sizeof(mod_Data)); data = xmalloc(sizeof(mod_Data));
data->audio_buffer = xmalloc(MIKMOD_FRAME_SIZE); data->audio_buffer = xmalloc(MIKMOD_FRAME_SIZE);
...@@ -177,6 +185,7 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path) ...@@ -177,6 +185,7 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
return -1; return -1;
} }
dc->totalTime = 0;
dc->audioFormat.bits = 16; dc->audioFormat.bits = 16;
dc->audioFormat.sampleRate = 44100; dc->audioFormat.sampleRate = 44100;
dc->audioFormat.channels = 2; dc->audioFormat.channels = 2;
...@@ -285,17 +294,6 @@ InputPlugin modPlugin = { ...@@ -285,17 +294,6 @@ InputPlugin modPlugin = {
#else #else
InputPlugin modPlugin = { InputPlugin modPlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_AUDIOFILE */ #endif /* HAVE_MIKMOD */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -31,6 +31,7 @@ ...@@ -31,6 +31,7 @@
#include "../utils.h" #include "../utils.h"
#include "../replayGain.h" #include "../replayGain.h"
#include "../tag.h" #include "../tag.h"
#include "../conf.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -55,6 +56,10 @@ ...@@ -55,6 +56,10 @@
/* the number of samples of silence the decoder inserts at start */ /* the number of samples of silence the decoder inserts at start */
#define DECODERDELAY 529 #define DECODERDELAY 529
#define DEFAULT_GAPLESS_MP3_PLAYBACK 1
static int gaplessPlayback;
/* this is stolen from mpg321! */ /* this is stolen from mpg321! */
struct audio_dither { struct audio_dither {
mad_fixed_t error[3]; mad_fixed_t error[3];
...@@ -113,6 +118,14 @@ static signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample, ...@@ -113,6 +118,14 @@ static signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample,
/* end of stolen stuff from mpg321 */ /* end of stolen stuff from mpg321 */
static int mp3_plugin_init(void)
{
gaplessPlayback = getBoolConfigParam(CONF_GAPLESS_MP3_PLAYBACK);
if (gaplessPlayback == -1) gaplessPlayback = DEFAULT_GAPLESS_MP3_PLAYBACK;
else if (gaplessPlayback < 0) exit(EXIT_FAILURE);
return 1;
}
/* decoder stuff is based on madlld */ /* decoder stuff is based on madlld */
#define MP3_DATA_OUTPUT_BUFFER_SIZE 4096 #define MP3_DATA_OUTPUT_BUFFER_SIZE 4096
...@@ -679,7 +692,8 @@ static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc, ...@@ -679,7 +692,8 @@ static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
data->foundXing = 1; data->foundXing = 1;
data->muteFrame = MUTEFRAME_SKIP; data->muteFrame = MUTEFRAME_SKIP;
if (parse_lame(&lame, &ptr, &bitlen)) { if (gaplessPlayback && data->inStream->seekable &&
parse_lame(&lame, &ptr, &bitlen)) {
data->dropSamplesAtStart = lame.encoderDelay + DECODERDELAY; data->dropSamplesAtStart = lame.encoderDelay + DECODERDELAY;
data->dropSamplesAtEnd = lame.encoderPadding; data->dropSamplesAtEnd = lame.encoderPadding;
} }
...@@ -759,8 +773,6 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, ...@@ -759,8 +773,6 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
mad_timer_add(&data->timer, (data->frame).header.duration); mad_timer_add(&data->timer, (data->frame).header.duration);
data->bitRate = (data->frame).header.bitrate; data->bitRate = (data->frame).header.bitrate;
if (data->currentFrame >= data->maxFrames) { if (data->currentFrame >= data->maxFrames) {
/* stop decoding, since Xing maxFrames is accurate */
if (data->foundXing) return DECODE_BREAK;
data->currentFrame = data->maxFrames - 1; data->currentFrame = data->maxFrames - 1;
} else { } else {
data->highestFrame++; data->highestFrame++;
...@@ -811,8 +823,9 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, ...@@ -811,8 +823,9 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
break; break;
} else if ((data->dropFramesAtEnd > 0) && } else if ((data->dropFramesAtEnd > 0) &&
(data->currentFrame == (data->maxFrames + 1 - data->dropFramesAtEnd))) { (data->currentFrame == (data->maxFrames + 1 - data->dropFramesAtEnd))) {
data->dropFramesAtEnd--; /* stop decoding, effectively dropping all remaining
break; * frames */
return DECODE_BREAK;
} }
if (data->inStream->metaTitle) { if (data->inStream->metaTitle) {
...@@ -835,59 +848,43 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, ...@@ -835,59 +848,43 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
for (i = 0; i < (data->synth).pcm.length; i++) { for (i = 0; i < (data->synth).pcm.length; i++) {
mpd_sint16 *sample; mpd_sint16 *sample;
samplesLeft--;
if (!data->decodedFirstFrame && if (!data->decodedFirstFrame &&
(i < data->dropSamplesAtStart)) { (i < data->dropSamplesAtStart)) {
continue; continue;
} else if (data->dropSamplesAtEnd && } else if (data->dropSamplesAtEnd &&
(data->currentFrame == (data->maxFrames - data->dropFramesAtEnd))) { (data->currentFrame == (data->maxFrames - data->dropFramesAtEnd)) &&
samplesLeft--; (samplesLeft < data->dropSamplesAtEnd)) {
/* stop decoding, since samples were dropped */ /* stop decoding, effectively dropping
if (samplesLeft < data->dropSamplesAtEnd) * all remaining samples */
return DECODE_BREAK; return DECODE_BREAK;
} }
sample = (mpd_sint16 *) data->outputPtr; sample = (mpd_sint16 *) data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16, *sample = (mpd_sint16) audio_linear_dither(16,
(data-> (data->synth).pcm.samples[0][i],
synth).pcm. &(data->dither));
samples[0]
[i],
&(data->
dither));
data->outputPtr += 2; data->outputPtr += 2;
if (MAD_NCHANNELS(&(data->frame).header) == 2) { if (MAD_NCHANNELS(&(data->frame).header) == 2) {
sample = (mpd_sint16 *) data->outputPtr; sample = (mpd_sint16 *) data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16, *sample = (mpd_sint16) audio_linear_dither(16,
(data-> (data->synth).pcm.samples[1][i],
synth). &(data->dither));
pcm.
samples
[1]
[i],
&
(data->
dither));
data->outputPtr += 2; data->outputPtr += 2;
} }
if (data->outputPtr >= data->outputBufferEnd) { if (data->outputPtr >= data->outputBufferEnd) {
long ret;
ret = sendDataToOutputBuffer(cb, ret = sendDataToOutputBuffer(cb,
data->inStream, data->inStream,
dc, dc,
data->inStream-> data->inStream->seekable,
seekable,
data->outputBuffer,
data->outputPtr -
data->outputBuffer, data->outputBuffer,
data->outputPtr - data->outputBuffer,
data->elapsedTime, data->elapsedTime,
data->bitRate / data->bitRate / 1000,
1000, (replayGainInfo != NULL) ? *replayGainInfo : NULL);
(replayGainInfo !=
NULL) ?
*replayGainInfo :
NULL);
if (ret == OUTPUT_BUFFER_DC_STOP) { if (ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0; data->flush = 0;
return DECODE_BREAK; return DECODE_BREAK;
...@@ -903,21 +900,21 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc, ...@@ -903,21 +900,21 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
data->decodedFirstFrame = 1; data->decodedFirstFrame = 1;
if (dc->seek && data->inStream->seekable) { if (dc->seek && data->inStream->seekable) {
long i = 0; long j = 0;
data->muteFrame = MUTEFRAME_SEEK; data->muteFrame = MUTEFRAME_SEEK;
while (i < data->highestFrame && dc->seekWhere > while (j < data->highestFrame && dc->seekWhere >
((float)mad_timer_count(data->times[i], ((float)mad_timer_count(data->times[j],
MAD_UNITS_MILLISECONDS)) MAD_UNITS_MILLISECONDS))
/ 1000) { / 1000) {
i++; j++;
} }
if (i < data->highestFrame) { if (j < data->highestFrame) {
if (seekMp3InputBuffer(data, if (seekMp3InputBuffer(data,
data->frameOffset[i]) == data->frameOffset[j]) ==
0) { 0) {
data->outputPtr = data->outputBuffer; data->outputPtr = data->outputBuffer;
clearOutputBuffer(cb); clearOutputBuffer(cb);
data->currentFrame = i; data->currentFrame = j;
} else } else
dc->seekError = 1; dc->seekError = 1;
data->muteFrame = 0; data->muteFrame = 0;
...@@ -1078,7 +1075,7 @@ static char *mp3_mimeTypes[] = { "audio/mpeg", NULL }; ...@@ -1078,7 +1075,7 @@ static char *mp3_mimeTypes[] = { "audio/mpeg", NULL };
InputPlugin mp3Plugin = { InputPlugin mp3Plugin = {
"mp3", "mp3",
NULL, mp3_plugin_init,
NULL, NULL,
NULL, NULL,
mp3_decode, mp3_decode,
...@@ -1090,17 +1087,6 @@ InputPlugin mp3Plugin = { ...@@ -1090,17 +1087,6 @@ InputPlugin mp3Plugin = {
}; };
#else #else
InputPlugin mp3Plugin = { InputPlugin mp3Plugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif #endif /* HAVE_MAD */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -100,7 +100,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char *path) ...@@ -100,7 +100,7 @@ static int mp4_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
faacDecConfigurationPtr config; faacDecConfigurationPtr config;
unsigned char *mp4Buffer; unsigned char *mp4Buffer;
unsigned int mp4BufferSize; unsigned int mp4BufferSize;
uint32_t sampleRate; unsigned long sampleRate;
unsigned char channels; unsigned char channels;
long sampleId; long sampleId;
long numSamples; long numSamples;
...@@ -450,17 +450,6 @@ InputPlugin mp4Plugin = { ...@@ -450,17 +450,6 @@ InputPlugin mp4Plugin = {
#else #else
InputPlugin mp4Plugin = { InputPlugin mp4Plugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif /* HAVE_FAAD */ #endif /* HAVE_FAAD */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -338,7 +338,6 @@ static MpdTag *mpcTagDup(char *file) ...@@ -338,7 +338,6 @@ static MpdTag *mpcTagDup(char *file)
} }
static char *mpcSuffixes[] = { "mpc", NULL }; static char *mpcSuffixes[] = { "mpc", NULL };
static char *mpcMimeTypes[] = { NULL };
InputPlugin mpcPlugin = { InputPlugin mpcPlugin = {
"mpc", "mpc",
...@@ -350,22 +349,11 @@ InputPlugin mpcPlugin = { ...@@ -350,22 +349,11 @@ InputPlugin mpcPlugin = {
mpcTagDup, mpcTagDup,
INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE, INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
mpcSuffixes, mpcSuffixes,
mpcMimeTypes NULL
}; };
#else #else
InputPlugin mpcPlugin = { InputPlugin mpcPlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
#endif #endif /* HAVE_MPCDEC */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* OggFLAC support (half-stolen from flac_plugin.c :)) * OggFLAC support (half-stolen from flac_plugin.c :))
...@@ -19,11 +19,10 @@ ...@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/ */
#include "../inputPlugin.h" #include "_flac_common.h"
#ifdef HAVE_OGGFLAC #ifdef HAVE_OGGFLAC
#include "_flac_common.h"
#include "_ogg_common.h" #include "_ogg_common.h"
#include "../utils.h" #include "../utils.h"
...@@ -37,8 +36,6 @@ ...@@ -37,8 +36,6 @@
#include <stdio.h> #include <stdio.h>
#include <string.h> #include <string.h>
#include <unistd.h> #include <unistd.h>
#include <OggFLAC/seekable_stream_decoder.h>
#include <FLAC/metadata.h>
static void oggflac_cleanup(InputStream * inStream, static void oggflac_cleanup(InputStream * inStream,
FlacData * data, FlacData * data,
...@@ -401,7 +398,10 @@ fail: ...@@ -401,7 +398,10 @@ fail:
} }
static char *oggflac_Suffixes[] = { "ogg", NULL }; static char *oggflac_Suffixes[] = { "ogg", NULL };
static char *oggflac_mime_types[] = { "application/ogg", NULL }; static char *oggflac_mime_types[] = { "audio/x-flac+ogg",
"application/ogg",
"application/x-ogg",
NULL };
InputPlugin oggflacPlugin = { InputPlugin oggflacPlugin = {
"oggflac", "oggflac",
...@@ -418,17 +418,6 @@ InputPlugin oggflacPlugin = { ...@@ -418,17 +418,6 @@ InputPlugin oggflacPlugin = {
#else /* !HAVE_FLAC */ #else /* !HAVE_FLAC */
InputPlugin oggflacPlugin = { InputPlugin oggflacPlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
#endif /* HAVE_OGGFLAC */ #endif /* HAVE_OGGFLAC */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -409,7 +409,10 @@ static unsigned int oggvorbis_try_decode(InputStream * inStream) ...@@ -409,7 +409,10 @@ static unsigned int oggvorbis_try_decode(InputStream * inStream)
} }
static char *oggvorbis_Suffixes[] = { "ogg", NULL }; static char *oggvorbis_Suffixes[] = { "ogg", NULL };
static char *oggvorbis_MimeTypes[] = { "application/ogg", NULL }; static char *oggvorbis_MimeTypes[] = { "application/ogg",
"audio/x-vorbis+ogg",
"application/x-ogg",
NULL };
InputPlugin oggvorbisPlugin = { InputPlugin oggvorbisPlugin = {
"oggvorbis", "oggvorbis",
...@@ -426,17 +429,6 @@ InputPlugin oggvorbisPlugin = { ...@@ -426,17 +429,6 @@ InputPlugin oggvorbisPlugin = {
#else /* !HAVE_OGGVORBIS */ #else /* !HAVE_OGGVORBIS */
InputPlugin oggvorbisPlugin = { InputPlugin oggvorbisPlugin;
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
#endif /* HAVE_OGGVORBIS */ #endif /* HAVE_OGGVORBIS */
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -25,6 +25,8 @@ ...@@ -25,6 +25,8 @@
#include <sys/types.h> #include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <errno.h> #include <errno.h>
#define _XOPEN_SOURCE 600
#include <fcntl.h>
void inputStream_initFile(void) void inputStream_initFile(void)
{ {
...@@ -46,6 +48,10 @@ int inputStream_fileOpen(InputStream * inStream, char *filename) ...@@ -46,6 +48,10 @@ int inputStream_fileOpen(InputStream * inStream, char *filename)
inStream->size = ftell(fp); inStream->size = ftell(fp);
fseek(fp, 0, SEEK_SET); fseek(fp, 0, SEEK_SET);
#ifdef POSIX_FADV_SEQUENTIAL
posix_fadvise(fileno(fp), (off_t)0, inStream->size, POSIX_FADV_SEQUENTIAL);
#endif
inStream->data = fp; inStream->data = fp;
inStream->seekFunc = inputStream_fileSeek; inStream->seekFunc = inputStream_fileSeek;
inStream->closeFunc = inputStream_fileClose; inStream->closeFunc = inputStream_fileClose;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -47,10 +47,10 @@ ...@@ -47,10 +47,10 @@
#define HTTP_REDIRECT_MAX 10 #define HTTP_REDIRECT_MAX 10
static char *proxyHost = NULL; static char *proxyHost;
static char *proxyPort = NULL; static char *proxyPort;
static char *proxyUser = NULL; static char *proxyUser;
static char *proxyPassword = NULL; static char *proxyPassword;
static int bufferSize = HTTP_BUFFER_SIZE_DEFAULT; static int bufferSize = HTTP_BUFFER_SIZE_DEFAULT;
static int prebufferSize = HTTP_PREBUFFER_SIZE_DEFAULT; static int prebufferSize = HTTP_PREBUFFER_SIZE_DEFAULT;
...@@ -81,9 +81,8 @@ void inputStream_initHttp(void) ...@@ -81,9 +81,8 @@ void inputStream_initHttp(void)
param = getConfigParam(CONF_HTTP_PROXY_PORT); param = getConfigParam(CONF_HTTP_PROXY_PORT);
if (!param) { if (!param) {
ERROR("%s specified but not %s", CONF_HTTP_PROXY_HOST, FATAL("%s specified but not %s", CONF_HTTP_PROXY_HOST,
CONF_HTTP_PROXY_PORT); CONF_HTTP_PROXY_PORT);
exit(EXIT_FAILURE);
} }
proxyPort = param->value; proxyPort = param->value;
...@@ -95,35 +94,30 @@ void inputStream_initHttp(void) ...@@ -95,35 +94,30 @@ void inputStream_initHttp(void)
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD); param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
if (!param) { if (!param) {
ERROR("%s specified but not %s\n", FATAL("%s specified but not %s\n",
CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_USER,
CONF_HTTP_PROXY_PASSWORD); CONF_HTTP_PROXY_PASSWORD);
exit(EXIT_FAILURE);
} }
proxyPassword = param->value; proxyPassword = param->value;
} } else {
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
if (param) { if (param) {
ERROR("%s specified but not %s\n", FATAL("%s specified but not %s\n",
CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER); CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
exit(EXIT_FAILURE); }
} }
} else if ((param = getConfigParam(CONF_HTTP_PROXY_PORT))) { } else if ((param = getConfigParam(CONF_HTTP_PROXY_PORT))) {
ERROR("%s specified but not %s, line %i\n", FATAL("%s specified but not %s, line %i\n",
CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST, param->line); CONF_HTTP_PROXY_PORT, CONF_HTTP_PROXY_HOST, param->line);
exit(EXIT_FAILURE);
} else if ((param = getConfigParam(CONF_HTTP_PROXY_USER))) { } else if ((param = getConfigParam(CONF_HTTP_PROXY_USER))) {
ERROR("%s specified but not %s, line %i\n", FATAL("%s specified but not %s, line %i\n",
CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST, param->line); CONF_HTTP_PROXY_USER, CONF_HTTP_PROXY_HOST, param->line);
exit(EXIT_FAILURE);
} else if ((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) { } else if ((param = getConfigParam(CONF_HTTP_PROXY_PASSWORD))) {
ERROR("%s specified but not %s, line %i\n", FATAL("%s specified but not %s, line %i\n",
CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST, CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_HOST,
param->line); param->line);
exit(EXIT_FAILURE);
} }
param = getConfigParam(CONF_HTTP_BUFFER_SIZE); param = getConfigParam(CONF_HTTP_BUFFER_SIZE);
...@@ -132,10 +126,9 @@ void inputStream_initHttp(void) ...@@ -132,10 +126,9 @@ void inputStream_initHttp(void)
bufferSize = strtol(param->value, &test, 10); bufferSize = strtol(param->value, &test, 10);
if (bufferSize <= 0 || *test != '\0') { if (bufferSize <= 0 || *test != '\0') {
ERROR("\"%s\" specified for %s at line %i is not a " FATAL("\"%s\" specified for %s at line %i is not a "
"positive integer\n", "positive integer\n",
param->value, CONF_HTTP_BUFFER_SIZE, param->line); param->value, CONF_HTTP_BUFFER_SIZE, param->line);
exit(EXIT_FAILURE);
} }
bufferSize *= 1024; bufferSize *= 1024;
...@@ -150,11 +143,10 @@ void inputStream_initHttp(void) ...@@ -150,11 +143,10 @@ void inputStream_initHttp(void)
prebufferSize = strtol(param->value, &test, 10); prebufferSize = strtol(param->value, &test, 10);
if (prebufferSize <= 0 || *test != '\0') { if (prebufferSize <= 0 || *test != '\0') {
ERROR("\"%s\" specified for %s at line %i is not a " FATAL("\"%s\" specified for %s at line %i is not a "
"positive integer\n", "positive integer\n",
param->value, CONF_HTTP_PREBUFFER_SIZE, param->value, CONF_HTTP_PREBUFFER_SIZE,
param->line); param->line);
exit(EXIT_FAILURE);
} }
prebufferSize *= 1024; prebufferSize *= 1024;
...@@ -446,7 +438,8 @@ static int finishHTTPInit(InputStream * inStream) ...@@ -446,7 +438,8 @@ static int finishHTTPInit(InputStream * inStream)
int error; int error;
socklen_t error_len = sizeof(int); socklen_t error_len = sizeof(int);
int ret; int ret;
char request[2049]; int length;
char request[2048];
tv.tv_sec = 0; tv.tv_sec = 0;
tv.tv_usec = 0; tv.tv_usec = 0;
...@@ -463,42 +456,41 @@ static int finishHTTPInit(InputStream * inStream) ...@@ -463,42 +456,41 @@ static int finishHTTPInit(InputStream * inStream)
if (ret < 0) { if (ret < 0) {
DEBUG(__FILE__ ": problem select'ing: %s\n", strerror(errno)); DEBUG(__FILE__ ": problem select'ing: %s\n", strerror(errno));
close(data->sock); goto close_err;
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
} }
getsockopt(data->sock, SOL_SOCKET, SO_ERROR, &error, &error_len); getsockopt(data->sock, SOL_SOCKET, SO_ERROR, &error, &error_len);
if (error) { if (error)
close(data->sock); goto close_err;
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
}
memset(request, 0, 2049);
/* deal with ICY metadata later, for now its fucking up stuff! */ /* deal with ICY metadata later, for now its fucking up stuff! */
snprintf(request, 2048, "GET %s HTTP/1.0\r\n" "Host: %s\r\n" length = snprintf(request, sizeof(request),
/*"Connection: close\r\n" */ "GET %s HTTP/1.1\r\n" "Host: %s\r\n"
"User-Agent: %s/%s\r\n" /*"Connection: close\r\n" */
/*"Range: bytes=%ld-\r\n" */ "User-Agent: %s/%s\r\n"
"%s" /* authorization */ "Range: bytes=%ld-\r\n"
"Icy-Metadata:1\r\n" "%s" /* authorization */
"\r\n", data->path, data->host, PACKAGE_NAME, PACKAGE_VERSION, "Icy-Metadata:1\r\n"
/*inStream->offset, */ "\r\n",
data->proxyAuth ? data->proxyAuth : data->path, data->host,
(data->httpAuth ? data->httpAuth : "") PACKAGE_NAME, PACKAGE_VERSION,
); inStream->offset,
data->proxyAuth ? data->proxyAuth :
ret = write(data->sock, request, strlen(request)); (data->httpAuth ? data->httpAuth : ""));
if (ret != strlen(request)) {
close(data->sock); if (length >= sizeof(request))
data->connState = HTTP_CONN_STATE_CLOSED; goto close_err;
return -1; ret = write(data->sock, request, length);
} if (ret != length)
goto close_err;
data->connState = HTTP_CONN_STATE_HELLO; data->connState = HTTP_CONN_STATE_HELLO;
return 0; return 0;
close_err:
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
} }
static int getHTTPHello(InputStream * inStream) static int getHTTPHello(InputStream * inStream)
...@@ -681,9 +673,6 @@ static int getHTTPHello(InputStream * inStream) ...@@ -681,9 +673,6 @@ static int getHTTPHello(InputStream * inStream)
data->prebuffer = 1; data->prebuffer = 1;
/*mark as unseekable till we actually implement seeking */
inStream->seekable = 0;
return 0; return 0;
} }
...@@ -714,21 +703,33 @@ int inputStream_httpOpen(InputStream * inStream, char *url) ...@@ -714,21 +703,33 @@ int inputStream_httpOpen(InputStream * inStream, char *url)
int inputStream_httpSeek(InputStream * inStream, long offset, int whence) int inputStream_httpSeek(InputStream * inStream, long offset, int whence)
{ {
/* hack to reopen an HTTP stream if we're trying to seek to InputStreamHTTPData *data;
* the beginning */
if ((whence == SEEK_SET) && (offset == 0)) {
InputStreamHTTPData *data;
data = (InputStreamHTTPData *) inStream->data; if (!inStream->seekable)
close(data->sock); return -1;
data->connState = HTTP_CONN_STATE_REOPEN;
data->buflen = 0; switch (whence) {
inStream->offset = 0; case SEEK_SET:
return 0; inStream->offset = offset;
break;
case SEEK_CUR:
inStream->offset += offset;
break;
case SEEK_END:
inStream->offset = inStream->size + offset;
break;
default:
return -1;
} }
/* otherwise, we don't know how to seek in HTTP yet */ data = (InputStreamHTTPData *)inStream->data;
return -1; close(data->sock);
data->connState = HTTP_CONN_STATE_REOPEN;
data->buflen = 0;
inputStream_httpBuffer(inStream);
return 0;
} }
static void parseIcyMetadata(InputStream * inStream, char *metadata, int size) static void parseIcyMetadata(InputStream * inStream, char *metadata, int size)
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "permission.h" #include "permission.h"
#include "sllist.h" #include "sllist.h"
#include "utils.h" #include "utils.h"
#include "ioops.h"
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
...@@ -55,20 +56,23 @@ ...@@ -55,20 +56,23 @@
#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024) #define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
/* set this to zero to indicate we have no possible interfaces */ /* set this to zero to indicate we have no possible interfaces */
static int interface_max_connections = 0; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */ static int interface_max_connections; /*INTERFACE_MAX_CONNECTIONS_DEFAULT; */
static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT; static int interface_timeout = INTERFACE_TIMEOUT_DEFAULT;
static size_t interface_max_command_list_size = static size_t interface_max_command_list_size =
INTERFACE_MAX_COMMAND_LIST_DEFAULT; INTERFACE_MAX_COMMAND_LIST_DEFAULT;
static size_t interface_max_output_buffer_size = static size_t interface_max_output_buffer_size =
INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT; INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT;
/* List of registered external IO handlers */
static struct ioOps *ioList;
/* maybe make conf option for this, or... 32 might be good enough */ /* maybe make conf option for this, or... 32 might be good enough */
static long int interface_list_cache_size = 32; static long int interface_list_cache_size = 32;
/* shared globally between all interfaces: */ /* shared globally between all interfaces: */
static struct strnode *list_cache = NULL; static struct strnode *list_cache;
static struct strnode *list_cache_head = NULL; static struct strnode *list_cache_head;
static struct strnode *list_cache_tail = NULL; static struct strnode *list_cache_tail;
typedef struct _Interface { typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH]; char buffer[INTERFACE_MAX_BUFFER_LENGTH];
...@@ -94,7 +98,7 @@ typedef struct _Interface { ...@@ -94,7 +98,7 @@ typedef struct _Interface {
int send_buf_alloc; /* bytes actually allocated */ int send_buf_alloc; /* bytes actually allocated */
} Interface; } Interface;
static Interface *interfaces = NULL; static Interface *interfaces;
static void flushInterfaceBuffer(Interface * interface); static void flushInterfaceBuffer(Interface * interface);
...@@ -489,6 +493,7 @@ int doIOForInterfaces(void) ...@@ -489,6 +493,7 @@ int doIOForInterfaces(void)
{ {
fd_set rfds; fd_set rfds;
fd_set wfds; fd_set wfds;
fd_set efds;
struct timeval tv; struct timeval tv;
int i; int i;
int selret; int selret;
...@@ -500,12 +505,43 @@ int doIOForInterfaces(void) ...@@ -500,12 +505,43 @@ int doIOForInterfaces(void)
while (1) { while (1) {
fdmax = 0; fdmax = 0;
FD_ZERO( &rfds );
FD_ZERO( &wfds );
FD_ZERO( &efds );
addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax); addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &fdmax);
addInterfacesForBufferFlushToFdSet(&wfds, &fdmax); addInterfacesForBufferFlushToFdSet(&wfds, &fdmax);
selret = select(fdmax + 1, &rfds, &wfds, NULL, &tv); /* Add fds for all registered IO handlers */
if( ioList ) {
struct ioOps *o = ioList;
while( o ) {
struct ioOps *current = o;
int fdnum;
assert( current->fdset );
fdnum = current->fdset( &rfds, &wfds, &efds );
if( fdmax < fdnum )
fdmax = fdnum;
o = o->next;
}
}
selret = select(fdmax + 1, &rfds, &wfds, &efds, &tv);
if (selret < 0 && errno == EINTR)
break;
/* Consume fds for all registered IO handlers */
if( ioList ) {
struct ioOps *o = ioList;
while( o ) {
struct ioOps *current = o;
assert( current->consume );
selret = current->consume( selret, &rfds, &wfds, &efds );
o = o->next;
}
}
if (selret == 0 || (selret < 0 && errno == EINTR)) if (selret == 0)
break; break;
if (selret < 0) { if (selret < 0) {
...@@ -549,10 +585,9 @@ void initInterfaces(void) ...@@ -549,10 +585,9 @@ void initInterfaces(void)
if (param) { if (param) {
interface_timeout = strtol(param->value, &test, 10); interface_timeout = strtol(param->value, &test, 10);
if (*test != '\0' || interface_timeout <= 0) { if (*test != '\0' || interface_timeout <= 0) {
ERROR("connection timeout \"%s\" is not a positive " FATAL("connection timeout \"%s\" is not a positive "
"integer, line %i\n", CONF_CONN_TIMEOUT, "integer, line %i\n", CONF_CONN_TIMEOUT,
param->line); param->line);
exit(EXIT_FAILURE);
} }
} }
...@@ -561,9 +596,8 @@ void initInterfaces(void) ...@@ -561,9 +596,8 @@ void initInterfaces(void)
if (param) { if (param) {
interface_max_connections = strtol(param->value, &test, 10); interface_max_connections = strtol(param->value, &test, 10);
if (*test != '\0' || interface_max_connections <= 0) { if (*test != '\0' || interface_max_connections <= 0) {
ERROR("max connections \"%s\" is not a positive integer" FATAL("max connections \"%s\" is not a positive integer"
", line %i\n", param->value, param->line); ", line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
} }
} else } else
interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT; interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
...@@ -574,9 +608,8 @@ void initInterfaces(void) ...@@ -574,9 +608,8 @@ void initInterfaces(void)
interface_max_command_list_size = strtol(param->value, interface_max_command_list_size = strtol(param->value,
&test, 10); &test, 10);
if (*test != '\0' || interface_max_command_list_size <= 0) { if (*test != '\0' || interface_max_command_list_size <= 0) {
ERROR("max command list size \"%s\" is not a positive " FATAL("max command list size \"%s\" is not a positive "
"integer, line %i\n", param->value, param->line); "integer, line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
} }
interface_max_command_list_size *= 1024; interface_max_command_list_size *= 1024;
} }
...@@ -587,9 +620,8 @@ void initInterfaces(void) ...@@ -587,9 +620,8 @@ void initInterfaces(void)
interface_max_output_buffer_size = strtol(param->value, interface_max_output_buffer_size = strtol(param->value,
&test, 10); &test, 10);
if (*test != '\0' || interface_max_output_buffer_size <= 0) { if (*test != '\0' || interface_max_output_buffer_size <= 0) {
ERROR("max output buffer size \"%s\" is not a positive " FATAL("max output buffer size \"%s\" is not a positive "
"integer, line %i\n", param->value, param->line); "integer, line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
} }
interface_max_output_buffer_size *= 1024; interface_max_output_buffer_size *= 1024;
} }
...@@ -696,7 +728,7 @@ static void flushInterfaceBuffer(Interface * interface) ...@@ -696,7 +728,7 @@ static void flushInterfaceBuffer(Interface * interface)
int interfacePrintWithFD(int fd, char *buffer, int buflen) int interfacePrintWithFD(int fd, char *buffer, int buflen)
{ {
static int i = 0; static int i;
int copylen; int copylen;
Interface *interface; Interface *interface;
...@@ -795,3 +827,25 @@ static void printInterfaceOutBuffer(Interface * interface) ...@@ -795,3 +827,25 @@ static void printInterfaceOutBuffer(Interface * interface)
interface->send_buf_used = 0; interface->send_buf_used = 0;
} }
/* From ioops.h: */
void registerIO( struct ioOps *ops )
{
assert( ops != NULL );
ops->next = ioList;
ioList = ops;
ops->prev = NULL;
if( ops->next )
ops->next->prev = ops;
}
void deregisterIO( struct ioOps *ops )
{
assert( ops != NULL );
if( ioList == ops )
ioList = ops->next;
else if( ops->prev != NULL )
ops->prev->next = ops->next;
}
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD)
* Copyright (C) 2003-2007 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 IOOPS_H
#define IOOPS_H
#include <sys/select.h>
struct ioOps {
struct ioOps *prev, *next;
/*
* Called before each 'select' statement.
* To register for IO, call FD_SET for each required queue
* Return the highest fd number you registered
*/
int (*fdset) ( fd_set *rfds, fd_set *wfds, fd_set *efds );
/*
* Called after each 'select' statement.
* fdCount is the number of fds total in all sets. It may be 0.
* For each fd you registered for in (fdset), you should FD_CLR it from the
* appropriate queue(s).
* Return the total number of fds left in all sets (Ie, return fdCount
* minus the number of times you called FD_CLR).
*/
int (*consume) ( int fdCount, fd_set *rfds, fd_set *wfds, fd_set *efds );
};
/* Call this to register your io operation handler struct */
void registerIO( struct ioOps *ops );
/* Call this to deregister your io operation handler struct */
void deregisterIO( struct ioOps *ops );
#endif
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -53,7 +53,7 @@ typedef struct _List { ...@@ -53,7 +53,7 @@ typedef struct _List {
ListNode **nodesArray; ListNode **nodesArray;
/* sorted */ /* sorted */
int sorted; int sorted;
/* weather to strdup() key's on insertion */ /* whether to strdup() key's on insertion */
int strdupKeys; int strdupKeys;
} List; } List;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -41,17 +41,19 @@ ...@@ -41,17 +41,19 @@
#define DEFAULT_PORT 6600 #define DEFAULT_PORT 6600
#define BINDERROR() do { \ #define BINDERROR() do { \
ERROR("unable to bind port %u: %s\n", port, strerror(errno)); \ FATAL("unable to bind port %u: %s\n" \
ERROR("maybe MPD is still running?\n"); \ "maybe MPD is still running?\n", \
port, strerror(errno)); \
} while (0); } while (0);
int *listenSockets = NULL; static int *listenSockets;
int numberOfListenSockets = 0; static int numberOfListenSockets;
static int boundPort;
static int establishListen(unsigned int port, static int establishListen(unsigned int port,
struct sockaddr *addrp, socklen_t addrlen) struct sockaddr *addrp, socklen_t addrlen)
{ {
int pf; int pf = 0;
int sock; int sock;
int allowReuse = ALLOW_REUSE; int allowReuse = ALLOW_REUSE;
...@@ -68,25 +70,20 @@ static int establishListen(unsigned int port, ...@@ -68,25 +70,20 @@ static int establishListen(unsigned int port,
pf = PF_UNIX; pf = PF_UNIX;
break; break;
default: default:
ERROR("unknown address family: %i\n", addrp->sa_family); FATAL("unknown address family: %i\n", addrp->sa_family);
exit(EXIT_FAILURE);
} }
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0) { if ((sock = socket(pf, SOCK_STREAM, 0)) < 0)
ERROR("socket < 0\n"); FATAL("socket < 0\n");
exit(EXIT_FAILURE);
}
if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) { if (fcntl(sock, F_SETFL, fcntl(sock, F_GETFL) | O_NONBLOCK) < 0) {
ERROR("problems setting nonblocking on listen socket: %s\n", FATAL("problems setting nonblocking on listen socket: %s\n",
strerror(errno)); strerror(errno));
exit(EXIT_FAILURE);
} }
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&allowReuse, if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&allowReuse,
sizeof(allowReuse)) < 0) { sizeof(allowReuse)) < 0) {
ERROR("problems setsockopt'ing: %s\n", strerror(errno)); FATAL("problems setsockopt'ing: %s\n", strerror(errno));
exit(EXIT_FAILURE);
} }
if (bind(sock, addrp, addrlen) < 0) { if (bind(sock, addrp, addrlen) < 0) {
...@@ -94,10 +91,8 @@ static int establishListen(unsigned int port, ...@@ -94,10 +91,8 @@ static int establishListen(unsigned int port,
return -1; return -1;
} }
if (listen(sock, 5) < 0) { if (listen(sock, 5) < 0)
ERROR("problems listen'ing: %s\n", strerror(errno)); FATAL("problems listen'ing: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
numberOfListenSockets++; numberOfListenSockets++;
listenSockets = listenSockets =
...@@ -110,8 +105,8 @@ static int establishListen(unsigned int port, ...@@ -110,8 +105,8 @@ static int establishListen(unsigned int port,
static void parseListenConfigParam(unsigned int port, ConfigParam * param) static void parseListenConfigParam(unsigned int port, ConfigParam * param)
{ {
struct sockaddr *addrp; struct sockaddr *addrp = NULL;
socklen_t addrlen; socklen_t addrlen = 0;
struct sockaddr_in sin; struct sockaddr_in sin;
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
struct sockaddr_in6 sin6; struct sockaddr_in6 sin6;
...@@ -132,10 +127,8 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param) ...@@ -132,10 +127,8 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
sin6.sin6_addr = in6addr_any; sin6.sin6_addr = in6addr_any;
addrp = (struct sockaddr *)&sin6; addrp = (struct sockaddr *)&sin6;
addrlen = sizeof(struct sockaddr_in6); addrlen = sizeof(struct sockaddr_in6);
if (establishListen(port, addrp, addrlen) < 0) { if (establishListen(port, addrp, addrlen) < 0)
BINDERROR(); BINDERROR();
exit(EXIT_FAILURE);
}
} }
#endif #endif
sin.sin_addr.s_addr = INADDR_ANY; sin.sin_addr.s_addr = INADDR_ANY;
...@@ -147,24 +140,21 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param) ...@@ -147,24 +140,21 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
if (establishListen(port, addrp, addrlen) < 0) { if (establishListen(port, addrp, addrlen) < 0) {
#endif #endif
BINDERROR(); BINDERROR();
exit(EXIT_FAILURE);
} }
} else { } else {
struct hostent *he; struct hostent *he;
DEBUG("binding to address for %s\n", param->value); DEBUG("binding to address for %s\n", param->value);
if (!(he = gethostbyname(param->value))) { if (!(he = gethostbyname(param->value))) {
ERROR("can't lookup host \"%s\" at line %i\n", FATAL("can't lookup host \"%s\" at line %i\n",
param->value, param->line); param->value, param->line);
exit(EXIT_FAILURE);
} }
switch (he->h_addrtype) { switch (he->h_addrtype) {
#ifdef HAVE_IPV6 #ifdef HAVE_IPV6
case AF_INET6: case AF_INET6:
if (!useIpv6) { if (!useIpv6) {
ERROR("no IPv6 support, but a IPv6 address " FATAL("no IPv6 support, but a IPv6 address "
"found for \"%s\" at line %i\n", "found for \"%s\" at line %i\n",
param->value, param->line); param->value, param->line);
exit(EXIT_FAILURE);
} }
memcpy((char *)&sin6.sin6_addr.s6_addr, memcpy((char *)&sin6.sin6_addr.s6_addr,
(char *)he->h_addr, he->h_length); (char *)he->h_addr, he->h_length);
...@@ -179,15 +169,12 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param) ...@@ -179,15 +169,12 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
addrlen = sizeof(struct sockaddr_in); addrlen = sizeof(struct sockaddr_in);
break; break;
default: default:
ERROR("address type for \"%s\" is not IPv4 or IPv6 " FATAL("address type for \"%s\" is not IPv4 or IPv6 "
"at line %i\n", param->value, param->line); "at line %i\n", param->value, param->line);
exit(EXIT_FAILURE);
} }
if (establishListen(port, addrp, addrlen) < 0) { if (establishListen(port, addrp, addrlen) < 0)
BINDERROR(); BINDERROR();
exit(EXIT_FAILURE);
}
} }
} }
...@@ -195,22 +182,20 @@ void listenOnPort(void) ...@@ -195,22 +182,20 @@ void listenOnPort(void)
{ {
int port = DEFAULT_PORT; int port = DEFAULT_PORT;
ConfigParam *param = getNextConfigParam(CONF_BIND_TO_ADDRESS, NULL); ConfigParam *param = getNextConfigParam(CONF_BIND_TO_ADDRESS, NULL);
ConfigParam *portParam = getConfigParam(CONF_PORT);
{
ConfigParam *portParam = getConfigParam(CONF_PORT); if (portParam) {
char *test;
if (portParam) { port = strtol(portParam->value, &test, 10);
char *test; if (port <= 0 || *test != '\0') {
port = strtol(portParam->value, &test, 10); FATAL("%s \"%s\" specified at line %i is not a "
if (port <= 0 || *test != '\0') { "positive integer", CONF_PORT,
ERROR("%s \"%s\" specified at line %i is not a " portParam->value, portParam->line);
"positive integer", CONF_PORT,
portParam->value, portParam->line);
exit(EXIT_FAILURE);
}
} }
} }
boundPort = port;
do { do {
parseListenConfigParam(port, param); parseListenConfigParam(port, param);
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param))); } while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
...@@ -266,3 +251,8 @@ void getConnections(fd_set * fds) ...@@ -266,3 +251,8 @@ void getConnections(fd_set * fds)
} }
} }
} }
int getBoundPort(void)
{
return boundPort;
}
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -36,4 +36,6 @@ void freeAllListenSockets(void); ...@@ -36,4 +36,6 @@ void freeAllListenSockets(void);
/* fdmax should be initialized to something */ /* fdmax should be initialized to something */
void addListenSocketsToFdSet(fd_set * fds, int *fdmax); void addListenSocketsToFdSet(fd_set * fds, int *fdmax);
int getBoundPort(void);
#endif #endif
/* the Music Player Daemon (MPD)
* (c)2007 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 "locate.h"
#include "utils.h"
#define LOCATE_TAG_FILE_KEY "file"
#define LOCATE_TAG_FILE_KEY_OLD "filename"
#define LOCATE_TAG_ANY_KEY "any"
int getLocateTagItemType(char *str)
{
int i;
if (0 == strcasecmp(str, LOCATE_TAG_FILE_KEY) ||
0 == strcasecmp(str, LOCATE_TAG_FILE_KEY_OLD))
{
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 = xstrdup(needle);
return 0;
}
LocateTagItem *newLocateTagItem(char *typeStr, char *needle)
{
LocateTagItem *ret = xmalloc(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 = xmalloc(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 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;
}
int strstrSearchTags(Song * song, int numItems, LocateTagItem * items)
{
int i;
for (i = 0; i < numItems; i++) {
if (!strstrSearchTag(song, items[i].tagType,
items[i].needle)) {
return 0;
}
}
return 1;
}
static int tagItemFoundAndMatches(Song * song, int type, char *str)
{
int i;
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
if (0 == strcmp(str, getSongUrl(song)))
return 1;
if (type == LOCATE_TAG_FILE_TYPE)
return 0;
}
if (!song->tag)
return 0;
for (i = 0; i < song->tag->numOfItems; i++) {
if (type != LOCATE_TAG_ANY_TYPE &&
song->tag->items[i].type != type) {
continue;
}
if (0 == strcmp(str, song->tag->items[i].value))
return 1;
}
return 0;
}
int tagItemsFoundAndMatches(Song * song, int numItems, LocateTagItem * items)
{
int i;
for (i = 0; i < numItems; i++) {
if (!tagItemFoundAndMatches(song, items[i].tagType,
items[i].needle)) {
return 0;
}
}
return 1;
}
/* the Music Player Daemon (MPD)
* (c)2007 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 "song.h"
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
/* 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 strstrSearchTags(Song * song, int numItems, LocateTagItem * items);
int tagItemsFoundAndMatches(Song * song, int numItems, LocateTagItem * items);
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -29,13 +29,13 @@ ...@@ -29,13 +29,13 @@
#include <time.h> #include <time.h>
static unsigned int logLevel = LOG_LEVEL_LOW; static unsigned int logLevel = LOG_LEVEL_LOW;
static int warningFlushed = 0; static int warningFlushed;
static int stdout_mode = 1; static int stdout_mode = 1;
static char *warningBuffer = NULL; static char *warningBuffer;
static int out_fd = -1; static int out_fd = -1;
static int err_fd = -1; static int err_fd = -1;
static const char *out_filename = NULL; static const char *out_filename;
static const char *err_filename = NULL; static const char *err_filename;
/* redirect stdin to /dev/null to work around a libao bug */ /* redirect stdin to /dev/null to work around a libao bug */
static void redirect_stdin(void) static void redirect_stdin(void)
...@@ -59,7 +59,7 @@ static void redirect_logs(void) ...@@ -59,7 +59,7 @@ static void redirect_logs(void)
static const char *log_date(void) static const char *log_date(void)
{ {
static char buf[16] = { '\0' }; static char buf[16];
time_t t = time(NULL); time_t t = time(NULL);
strftime(buf, 16, "%b %d %H:%M : ", localtime(&t)); strftime(buf, 16, "%b %d %H:%M : ", localtime(&t));
return buf; return buf;
...@@ -68,7 +68,7 @@ static const char *log_date(void) ...@@ -68,7 +68,7 @@ static const char *log_date(void)
#define BUFFER_LENGTH 4096 #define BUFFER_LENGTH 4096
static void buffer_warning(const char *fmt, va_list args) static void buffer_warning(const char *fmt, va_list args)
{ {
char buffer[BUFFER_LENGTH + 1]; char buffer[BUFFER_LENGTH];
char *tmp = buffer; char *tmp = buffer;
size_t len = BUFFER_LENGTH; size_t len = BUFFER_LENGTH;
...@@ -100,11 +100,10 @@ void flushWarningLog(void) ...@@ -100,11 +100,10 @@ void flushWarningLog(void)
if (warningBuffer != NULL) if (warningBuffer != NULL)
{ {
while (s != NULL) { while (s != NULL) {
char * next = strchr(s, '\n'); char *next = strchr(s, '\n');
if (next != NULL) { if (next == NULL) break;
*next = '\0'; *next = '\0';
next++; next++;
}
fprintf(stderr, "%s\n", s); fprintf(stderr, "%s\n", s);
s = next; s = next;
} }
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -42,6 +42,7 @@ ...@@ -42,6 +42,7 @@
#include "../config.h" #include "../config.h"
#include "utils.h" #include "utils.h"
#include "normalize.h" #include "normalize.h"
#include "zeroconf.h"
#include <stdio.h> #include <stdio.h>
#include <sys/select.h> #include <sys/select.h>
...@@ -65,7 +66,6 @@ typedef struct _Options { ...@@ -65,7 +66,6 @@ typedef struct _Options {
int daemon; int daemon;
int stdOutput; int stdOutput;
int createDB; int createDB;
int updateDB;
int verbose; int verbose;
} Options; } Options;
...@@ -126,7 +126,6 @@ static void usage(char *argv[]) ...@@ -126,7 +126,6 @@ static void usage(char *argv[])
(" --no-create-db don't create database, even if it doesn't exist\n"); (" --no-create-db don't create database, even if it doesn't exist\n");
ERROR(" --no-daemon don't detach from console\n"); ERROR(" --no-daemon don't detach from console\n");
ERROR(" --stdout print messages to stdout and stderr\n"); ERROR(" --stdout print messages to stdout and stderr\n");
/*ERROR(" --update-db create database and exit\n"); */
ERROR(" --verbose verbose logging\n"); ERROR(" --verbose verbose logging\n");
ERROR(" --version prints version information\n"); ERROR(" --version prints version information\n");
} }
...@@ -135,7 +134,7 @@ static void version(void) ...@@ -135,7 +134,7 @@ static void version(void)
{ {
LOG("mpd (MPD: Music Player Daemon) %s\n", VERSION); LOG("mpd (MPD: Music Player Daemon) %s\n", VERSION);
LOG("\n"); LOG("\n");
LOG("Copyright (C) 2003-2006 Warren Dukes <warren.dukes@gmail.com>\n"); LOG("Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n");
LOG("This is free software; see the source for copying conditions. There is NO\n"); LOG("This is free software; see the source for copying conditions. There is NO\n");
LOG("warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"); LOG("warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
LOG("\n"); LOG("\n");
...@@ -158,7 +157,6 @@ static void parseOptions(int argc, char **argv, Options * options) ...@@ -158,7 +157,6 @@ static void parseOptions(int argc, char **argv, Options * options)
options->daemon = 1; options->daemon = 1;
options->stdOutput = 0; options->stdOutput = 0;
options->createDB = 0; options->createDB = 0;
options->updateDB = 0;
options->kill = 0; options->kill = 0;
if (argc > 1) { if (argc > 1) {
...@@ -248,15 +246,13 @@ static void changeToUser(void) ...@@ -248,15 +246,13 @@ static void changeToUser(void)
/* get uid */ /* get uid */
struct passwd *userpwd; struct passwd *userpwd;
if ((userpwd = getpwnam(param->value)) == NULL) { if ((userpwd = getpwnam(param->value)) == NULL) {
ERROR("no such user \"%s\" at line %i\n", param->value, FATAL("no such user \"%s\" at line %i\n", param->value,
param->line); param->line);
exit(EXIT_FAILURE);
} }
if (setgid(userpwd->pw_gid) == -1) { if (setgid(userpwd->pw_gid) == -1) {
ERROR("cannot setgid for user \"%s\" at line %i: %s\n", FATAL("cannot setgid for user \"%s\" at line %i: %s\n",
param->value, param->line, strerror(errno)); param->value, param->line, strerror(errno));
exit(EXIT_FAILURE);
} }
#ifdef _BSD_SOURCE #ifdef _BSD_SOURCE
/* init suplementary groups /* init suplementary groups
...@@ -271,10 +267,9 @@ static void changeToUser(void) ...@@ -271,10 +267,9 @@ static void changeToUser(void)
/* set uid */ /* set uid */
if (setuid(userpwd->pw_uid) == -1) { if (setuid(userpwd->pw_uid) == -1) {
ERROR("cannot change to uid of user " FATAL("cannot change to uid of user "
"\"%s\" at line %i: %s\n", "\"%s\" at line %i: %s\n",
param->value, param->line, strerror(errno)); param->value, param->line, strerror(errno));
exit(EXIT_FAILURE);
} }
/* this is needed by libs such as arts */ /* this is needed by libs such as arts */
...@@ -288,10 +283,9 @@ static void openDB(Options * options, char *argv0) ...@@ -288,10 +283,9 @@ static void openDB(Options * options, char *argv0)
{ {
if (options->createDB > 0 || readDirectoryDB() < 0) { if (options->createDB > 0 || readDirectoryDB() < 0) {
if (options->createDB < 0) { if (options->createDB < 0) {
ERROR("can't open db file and using \"--no-create-db\"" FATAL("can't open db file and using "
" command line option\n"); "\"--no-create-db\" command line option\n"
ERROR("try running \"%s --create-db\"\n", argv0); "try running \"%s --create-db\"\n", argv0);
exit(EXIT_FAILURE);
} }
flushWarningLog(); flushWarningLog();
if (checkDirectoryDB() < 0) if (checkDirectoryDB() < 0)
...@@ -302,11 +296,6 @@ static void openDB(Options * options, char *argv0) ...@@ -302,11 +296,6 @@ static void openDB(Options * options, char *argv0)
if (options->createDB) if (options->createDB)
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
if (options->updateDB) {
flushWarningLog();
updateMp3Directory();
exit(EXIT_SUCCESS);
}
} }
static void daemonize(Options * options) static void daemonize(Options * options)
...@@ -320,11 +309,9 @@ static void daemonize(Options * options) ...@@ -320,11 +309,9 @@ static void daemonize(Options * options)
DEBUG("opening pid file\n"); DEBUG("opening pid file\n");
fp = fopen(pidFileParam->value, "w+"); fp = fopen(pidFileParam->value, "w+");
if (!fp) { if (!fp) {
ERROR FATAL("could not open %s \"%s\" (at line %i) for writing: %s\n",
("could not open %s \"%s\" (at line %i) for writing: %s\n",
CONF_PID_FILE, pidFileParam->value, CONF_PID_FILE, pidFileParam->value,
pidFileParam->line, strerror(errno)); pidFileParam->line, strerror(errno));
exit(EXIT_FAILURE);
} }
} }
...@@ -336,18 +323,15 @@ static void daemonize(Options * options) ...@@ -336,18 +323,15 @@ static void daemonize(Options * options)
if (pid > 0) if (pid > 0)
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
else if (pid < 0) { else if (pid < 0) {
ERROR("problems fork'ing for daemon!\n"); FATAL("problems fork'ing for daemon!\n");
exit(EXIT_FAILURE);
} }
if (chdir("/") < 0) { if (chdir("/") < 0) {
ERROR("problems changing to root directory\n"); FATAL("problems changing to root directory\n");
exit(EXIT_FAILURE);
} }
if (setsid() < 0) { if (setsid() < 0) {
ERROR("problems setsid'ing\n"); FATAL("problems setsid'ing\n");
exit(EXIT_FAILURE);
} }
fflush(NULL); fflush(NULL);
...@@ -355,8 +339,7 @@ static void daemonize(Options * options) ...@@ -355,8 +339,7 @@ static void daemonize(Options * options)
if (pid > 0) if (pid > 0)
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
else if (pid < 0) { else if (pid < 0) {
ERROR("problems fork'ing for daemon!\n"); FATAL("problems fork'ing for daemon!\n");
exit(EXIT_FAILURE);
} }
DEBUG("daemonized!\n"); DEBUG("daemonized!\n");
...@@ -388,26 +371,22 @@ static void killFromPidFile(char *cmd, int killOption) ...@@ -388,26 +371,22 @@ static void killFromPidFile(char *cmd, int killOption)
int pid; int pid;
if (!pidFileParam) { if (!pidFileParam) {
ERROR("no pid_file specified in the config file\n"); FATAL("no pid_file specified in the config file\n");
exit(EXIT_FAILURE);
} }
fp = fopen(pidFileParam->value, "r"); fp = fopen(pidFileParam->value, "r");
if (!fp) { if (!fp) {
ERROR("unable to open %s \"%s\": %s\n", FATAL("unable to open %s \"%s\": %s\n",
CONF_PID_FILE, pidFileParam->value, strerror(errno)); CONF_PID_FILE, pidFileParam->value, strerror(errno));
exit(EXIT_FAILURE);
} }
if (fscanf(fp, "%i", &pid) != 1) { if (fscanf(fp, "%i", &pid) != 1) {
ERROR("unable to read the pid from file \"%s\"\n", FATAL("unable to read the pid from file \"%s\"\n",
pidFileParam->value); pidFileParam->value);
exit(EXIT_FAILURE);
} }
fclose(fp); fclose(fp);
if (kill(pid, SIGTERM)) { if (kill(pid, SIGTERM)) {
ERROR("unable to kill proccess %i: %s\n", pid, strerror(errno)); FATAL("unable to kill proccess %i: %s\n", pid, strerror(errno));
exit(EXIT_FAILURE);
} }
exit(EXIT_SUCCESS); exit(EXIT_SUCCESS);
} }
...@@ -430,7 +409,7 @@ int main(int argc, char *argv[]) ...@@ -430,7 +409,7 @@ int main(int argc, char *argv[])
initTagConfig(); initTagConfig();
initLog(options.verbose); initLog(options.verbose);
if (options.createDB <= 0 && !options.updateDB) if (options.createDB <= 0)
listenOnPort(); listenOnPort();
changeToUser(); changeToUser();
...@@ -450,6 +429,7 @@ int main(int argc, char *argv[]) ...@@ -450,6 +429,7 @@ int main(int argc, char *argv[])
initAudioDriver(); initAudioDriver();
initVolume(); initVolume();
initInterfaces(); initInterfaces();
initZeroconf();
initReplayGainState(); initReplayGainState();
initNormalization(); initNormalization();
initInputStream(); initInputStream();
...@@ -475,6 +455,7 @@ int main(int argc, char *argv[]) ...@@ -475,6 +455,7 @@ int main(int argc, char *argv[])
write_state_file(); write_state_file();
playerKill(); playerKill();
finishZeroconf();
freeAllInterfaces(); freeAllInterfaces();
closeAllListenSockets(); closeAllListenSockets();
finishPlaylist(); finishPlaylist();
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -50,7 +50,7 @@ static void blockingWrite(const int fd, const char *string, size_t len) ...@@ -50,7 +50,7 @@ static void blockingWrite(const int fd, const char *string, size_t len)
void vfdprintf(const int fd, const char *fmt, va_list args) void vfdprintf(const int fd, const char *fmt, va_list args)
{ {
static char buffer[BUFFER_LENGTH + 1]; static char buffer[BUFFER_LENGTH];
char *buf = buffer; char *buf = buffer;
size_t len; size_t len;
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
......
/* the Music Player Daemon (MPD) /* the Music Player Daemon (MPD)
* (c)2003-2006 by Warren Dukes (warren.dukes@gmail.com) * Copyright (C) 2003-2007 by Warren Dukes (warren.dukes@gmail.com)
* This project's homepage is: http://www.musicpd.org * This project's homepage is: http://www.musicpd.org
* *
* This program is free software; you can redistribute it and/or modify * This program is free software; you can redistribute it and/or modify
...@@ -30,7 +30,7 @@ ...@@ -30,7 +30,7 @@
static mpd_sint16 currentChunk = -1; static mpd_sint16 currentChunk = -1;
static mpd_sint8 currentMetaChunk = -1; static mpd_sint8 currentMetaChunk = -1;
static mpd_sint8 sendMetaChunk = 0; static mpd_sint8 sendMetaChunk;
void clearAllMetaChunkSets(OutputBuffer * cb) void clearAllMetaChunkSets(OutputBuffer * cb)
{ {
...@@ -58,11 +58,10 @@ void clearOutputBuffer(OutputBuffer * cb) ...@@ -58,11 +58,10 @@ void clearOutputBuffer(OutputBuffer * cb)
void flushOutputBuffer(OutputBuffer * cb) void flushOutputBuffer(OutputBuffer * cb)
{ {
if (currentChunk == cb->end) { if (currentChunk == cb->end) {
int next = cb->end + 1; if ((cb->end + 1) >= buffered_chunks) {
if (next >= buffered_chunks) { cb->end = 0;
next = 0;
} }
cb->end = next; else cb->end++;
currentChunk = -1; currentChunk = -1;
} }
} }
...@@ -76,27 +75,23 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, ...@@ -76,27 +75,23 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
mpd_uint16 chunkLeft; mpd_uint16 chunkLeft;
char *data; char *data;
size_t datalen; size_t datalen;
static char *convBuffer = NULL; static char *convBuffer;
static long convBufferLen = 0; static long convBufferLen;
if (cmpAudioFormat(&(cb->audioFormat), &(dc->audioFormat)) == 0) { if (cmpAudioFormat(&(cb->audioFormat), &(dc->audioFormat)) == 0) {
data = dataIn; data = dataIn;
datalen = dataInLen; datalen = dataInLen;
} else { } else {
datalen = datalen = pcm_sizeOfConvBuffer(&(dc->audioFormat), dataInLen,
pcm_sizeOfOutputBufferForAudioFormatConversion(& &(cb->audioFormat));
(dc->
audioFormat),
dataInLen,
&(cb->
audioFormat));
if (datalen > convBufferLen) { if (datalen > convBufferLen) {
convBuffer = xrealloc(convBuffer, datalen); convBuffer = xrealloc(convBuffer, datalen);
convBufferLen = datalen; convBufferLen = datalen;
} }
data = convBuffer; data = convBuffer;
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen, datalen = pcm_convertAudioFormat(&(dc->audioFormat), dataIn,
&(cb->audioFormat), data); dataInLen, &(cb->audioFormat),
data, &(cb->convState));
} }
if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF)) if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF))
...@@ -158,7 +153,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream, ...@@ -158,7 +153,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag) int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag)
{ {
int nextChunk; int nextChunk;
static MpdTag *last = NULL; static MpdTag *last;
if (!cb->acceptMetadata || !tag) { if (!cb->acceptMetadata || !tag) {
sendMetaChunk = 0; sendMetaChunk = 0;
......
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