Commit 1370cca9 authored by Led's avatar Led

0.13.0

parent ffeacd4b
Developer -> Warren Dukes <warren.dukes@gmail.com>
Developer -> tw-nym
audiofile support and command.c cleanup -> normalperson
setuid patch -> Nagilum
'next' and 'previous' patch -> Niklas Hofer
command.c and signal handling cleanup -> mackstann
replayGain -> AliasMrJones
Current Developers
------------------
Warren Dukes <warren.dukes@gmail.com>
general
J. Alexander Treuman <jat@spatialrift.net>
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
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)
* Fix a bug where clients could cause MPD to segfault
......@@ -15,7 +41,6 @@ ver 0.12.0 (2006/9/22)
* ALSA
* OSS
* OS X
* Sun
* Media MVP
* PulseAudio
* Shout (Icecast or Shoutcast)
......
......@@ -20,6 +20,9 @@ Linux. You will need libasound.
PulseAudio - http://www.pulseaudio.org/
An advanced sound daemon. You will need libpulse.
JACK - http://www.jackaudio.org/
A low-latency sound daemon.
libshout - http://www.icecast.org/
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.
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
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/
For WAVE, AIFF, and AU support. You will need libaudiofile.
......@@ -57,6 +61,15 @@ For Musepack support.
MikMod - http://mikmod.raphnet.net/
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
--------
......@@ -112,8 +125,7 @@ mp3's.
Using MPD
---------
You can download a web interface (phpMp) to MPD at <http://www.musicpd.org/>.
Also, several other clients can be found for MPD at <http://www.musicpd.org/>.
You can download many different interfaces for MPD at
<http://mpd.wikia.com/wiki/Clients>
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
A daemon for playing music (mp3, ogg vorbis, and flac). Music is played
through the server's audio device. The daemon stores info about all available
music, and this info can be easily searched and retrieved. Player control, info
A daemon for playing music of various formats. Music is played through the
server's audio device. The daemon stores info about all available music,
and this info can be easily searched and retrieved. Player control, info
retrieval, and playlist management can all be managed remotely.
To install MPD, see INSTALL.
MPD includes 3 libraries in the source. libid3tag and libmad are released under
the GPL and copyrighted by Robert Leslie (http://www.underbit.com/products/mad).
mp4ff is 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
MPD includes mp4ff in the source, due to licensing issues of the newer
version and includes bugfixes with the properly licensed version. mp4ff is
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
Advance Audio (AAC) Decoder.
MPD is released under the GNU Public License.
......
0.13
0.14
----
*) data structures
......@@ -16,7 +16,7 @@
*) cleanup linked list code!
*) 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
*) cleanup input plugins "API"
......@@ -29,7 +29,6 @@
*) audio output
*) write a esd native audioOutput
*) write a nas native audioOutput
*) need better resampling code
*) allowing "pausing" of audio output devices
*) while pausing, play silence for the devices that don't support
"pausing"
......@@ -41,17 +40,8 @@
*) abstract out state code from playlist.c
*) put MPD Version in statefile
*) rewrite saved playlist code
*) abstract out saved playlists from playlist.c
*) 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 playlistreplace command (replace current playlist with saved playlist
and keep playing)
*) add command for inserting songs in a specific position
......@@ -61,7 +51,7 @@
*) bug fixes
post-1.0
----
--------
*) rewrite audio pipe
*) use pthreads/clone
......
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
-------------------
......
......@@ -756,6 +756,46 @@ AC_CONFIG_COMMANDS_PRE(
Usually this means the macro was only invoked conditionally.])
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-*-
# serial 48 AC_PROG_LIBTOOL
......@@ -8066,7 +8106,7 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile
elif test "x$libFLAC_prefix" != "x" ; then
LIBFLAC_LIBS="-L$libFLAC_prefix/lib"
elif test "x$prefix" != "xNONE" ; then
LIBFLAC_LIBS="-L$prefix/lib"
LIBFLAC_LIBS="-L$libdir"
fi
LIBFLAC_LIBS="$LIBFLAC_LIBS -lFLAC -lm"
......@@ -8075,8 +8115,8 @@ AC_ARG_ENABLE(libFLACtest, [ --disable-libFLACtest Do not try to compile
LIBFLAC_CFLAGS="-I$libFLAC_includes"
elif test "x$libFLAC_prefix" != "x" ; then
LIBFLAC_CFLAGS="-I$libFLAC_prefix/include"
elif test "x$prefix" != "xNONE"; then
LIBFLAC_CFLAGS="-I$prefix/include"
elif test "$prefix" != "xNONE"; then
LIBFLAC_CFLAGS="-I$libdir"
fi
AC_MSG_CHECKING(for libFLAC)
......
......@@ -9,6 +9,9 @@
/* Define for audiofile support */
#undef HAVE_AUDIOFILE
/* Define to enable Avahi Zeroconf support */
#undef HAVE_AVAHI
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
......@@ -49,6 +52,9 @@
/* Define if IPv6 support present */
#undef HAVE_IPV6
/* Define to enable JACK support */
#undef HAVE_JACK
/* Define if you have <langinfo.h> and nl_langinfo(CODESET). */
#undef HAVE_LANGINFO_CODESET
......@@ -58,6 +64,9 @@
/* Define to 1 if you have the `FLAC' library (-lFLAC). */
#undef HAVE_LIBFLAC
/* Define to enable libsamplerate */
#undef HAVE_LIBSAMPLERATE
/* Define if locale.h is present */
#undef HAVE_LOCALE
......@@ -94,7 +103,7 @@
/* Define for compiling OS X support */
#undef HAVE_OSX
/* Define to enable PulseAudio */
/* Define to enable PulseAudio support */
#undef HAVE_PULSE
/* Define to 1 if you have the `setenv' function. */
......@@ -118,9 +127,6 @@
/* Define to 1 if you have the <string.h> header file. */
#undef HAVE_STRING_H
/* Define to enable SUN audio support */
#undef HAVE_SUN
/* Define if sys/inttypes.h present */
#undef HAVE_SYS_INTTYPES_H
......@@ -136,6 +142,9 @@
/* Define to 1 if you have the <unistd.h> header file. */
#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 */
#undef PACKAGE
......
......@@ -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
default is "default".
.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>
This specifies a password for access to mpd. The format is
"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
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.
.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>
This specifies which mixer to use. The default depends on what audio output
support mpd was built with.
......@@ -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.
.TP
.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
.B audio_buffer_size <size in KiB>
This specifies the size of the audio output buffer that mpd uses. The default
is 2048.
This specifies the size of the audio buffer in kibibytes. The default is 2048,
large enough for nearly 12 seconds of CD-quality audio.
.TP
.B buffer_before_play <0-100%>
This specifies the amount of the audio buffer that will be filled before a song
begins playing. The default is 25%.
This specifies how much of the audio buffer should be filled before playing a
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
.B http_buffer_size <size in KiB>
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
to let libid3tag convert them (from ISO-8859-1, as the standard specifies) and
do no additional conversion.
.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>
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
this parameter to take effect. Possible values are artist, album, title,
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
"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
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
.TP
.B type <type>
......@@ -215,11 +263,12 @@ whatever audio format is passed to the audio output.
.SH OPTIONAL ALSA OUTPUT PARAMETERS
.TP
.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
.B use_mmap <yes or no>
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
.B buffer_time <time in microseconds>
This sets the length of the hardware sample buffer in microseconds. Increasing
......@@ -246,6 +295,20 @@ default is to let PulseAudio choose a server.
.TP
.B sink <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
.TP
.B driver <driver>
......
......@@ -45,6 +45,12 @@ error_file "~/.mpd/mpd.error"
#
#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"
#
#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"
#audio_buffer_size "2048"
#
# 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
# skipping while playing HTTP streams, you may wish to increase
......@@ -233,13 +247,22 @@ error_file "~/.mpd/mpd.error"
######################### 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
# other music players.
#
#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 = \
audioOutputs/audioOutput_osx.c \
audioOutputs/audioOutput_pulse.c \
audioOutputs/audioOutput_mvp.c \
audioOutputs/audioOutput_shout.c
audioOutputs/audioOutput_shout.c \
audioOutputs/audioOutput_jack.c
mpd_inputPlugins = \
inputPlugins/_flac_common.c \
......@@ -71,7 +72,11 @@ mpd_headers = \
tree.h \
utf8.h \
utils.h \
volume.h
volume.h \
ioops.h \
zeroconf.h \
locate.h \
storedPlaylist.h
mpd_SOURCES = \
......@@ -120,7 +125,10 @@ mpd_SOURCES = \
tree.c \
utils.c \
volume.c \
utf8.c
utf8.c \
zeroconf.c \
locate.c \
storedPlaylist.c
mpd_CFLAGS = $(MPD_CFLAGS)
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -39,12 +39,12 @@
#define AUDIO_DEVICE_STATE_LEN 19 /* strlen(AUDIO_DEVICE_STATE) */
#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 mpd_uint8 audioOutputArraySize = 0;
static AudioOutput *audioOutputArray;
static mpd_uint8 audioOutputArraySize;
#define DEVICE_OFF 0x00
#define DEVICE_ENABLE 0x01 /* currently off, but to be turned on */
......@@ -53,13 +53,13 @@ static mpd_uint8 audioOutputArraySize = 0;
/* the audioEnabledArray should be stuck into shared memory, and then disable
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 char *audioBuffer = NULL;
static mpd_sint32 audioBufferPos = 0;
static mpd_sint32 audioBufferSize;
static char *audioBuffer;
static mpd_sint32 audioBufferPos;
size_t audio_device_count(void)
{
......@@ -89,14 +89,6 @@ int cmpAudioFormat(AudioFormat * f1, AudioFormat * f2)
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)
{
initAudioOutputPlugins();
......@@ -107,6 +99,7 @@ void loadAudioDrivers(void)
loadAudioOutputPlugin(&pulsePlugin);
loadAudioOutputPlugin(&mvpPlugin);
loadAudioOutputPlugin(&shoutPlugin);
loadAudioOutputPlugin(&jackPlugin);
}
/* make sure initPlayerData is called before this function!! */
......@@ -134,23 +127,21 @@ void initAudioDriver(void)
if (!initAudioOutput(output, param)) {
if (param)
{
ERROR("problems configuring output device "
FATAL("problems configuring output device "
"defined at line %i\n", param->line);
}
else
{
ERROR("No audio_output specified and unable to "
FATAL("No audio_output specified and unable to "
"detect a default audio output device\n");
}
exit(EXIT_FAILURE);
}
/* require output names to be unique: */
for (j = 0; j < i; j++) {
if (!strcmp(output->name, audioOutputArray[j].name)) {
ERROR("output devices with identical "
FATAL("output devices with identical "
"names: %s\n", output->name);
exit(EXIT_FAILURE);
}
}
audioDeviceStates[i] = DEVICE_ENABLE;
......@@ -176,9 +167,8 @@ void initAudioConfig(void)
audio_configFormat = xmalloc(sizeof(AudioFormat));
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);
exit(EXIT_FAILURE);
}
}
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -58,10 +58,9 @@ void finishAudioOutputPlugins(void)
#define getBlockParam(name, str, force) { \
bp = getBlockParam(param, name); \
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", \
name, param->line); \
exit(EXIT_FAILURE); \
} \
if(bp) str = bp->value; \
}
......@@ -81,9 +80,8 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
getBlockParam(AUDIO_OUTPUT_FORMAT, format, 0);
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);
exit(EXIT_FAILURE);
}
plugin = (AudioOutputPlugin *) data;
......@@ -135,13 +133,13 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
memset(&ao->inAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->outAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->reqAudioFormat, 0, sizeof(AudioFormat));
memset(&ao->convState, 0, sizeof(ConvState));
if (format) {
ao->convertAudioFormat = 1;
if (0 != parseAudioConfig(&ao->reqAudioFormat, format)) {
ERROR("error parsing format at line %i\n", bp->line);
exit(EXIT_FAILURE);
FATAL("error parsing format at line %i\n", bp->line);
}
copyAudioFormat(&ao->outAudioFormat, &ao->reqAudioFormat);
......@@ -155,33 +153,38 @@ int initAudioOutput(AudioOutput *ao, ConfigParam * param)
int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat)
{
int ret;
int ret = 0;
if (audioOutput->open) {
if (cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat)
== 0) {
if (audioOutput->open)
{
if (0==cmpAudioFormat(audioFormat, &audioOutput->inAudioFormat))
{
return 0;
}
closeAudioOutput(audioOutput);
}
copyAudioFormat(&audioOutput->inAudioFormat, audioFormat);
if (audioOutput->convertAudioFormat) {
if (audioOutput->convertAudioFormat)
{
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->reqAudioFormat);
} else {
}
else
{
copyAudioFormat(&audioOutput->outAudioFormat,
&audioOutput->inAudioFormat);
if (audioOutput->open) closeAudioOutput(audioOutput);
}
ret = audioOutput->openDeviceFunc(audioOutput);
if (!audioOutput->open)
{
ret = audioOutput->openDeviceFunc(audioOutput);
}
if (cmpAudioFormat(&audioOutput->inAudioFormat,
&audioOutput->outAudioFormat) == 0) {
audioOutput->sameInAndOutFormats = 1;
} else
audioOutput->sameInAndOutFormats = 0;
audioOutput->sameInAndOutFormats =
!cmpAudioFormat(&audioOutput->inAudioFormat,
&audioOutput->outAudioFormat);
return ret;
}
......@@ -189,12 +192,9 @@ int openAudioOutput(AudioOutput * audioOutput, AudioFormat * audioFormat)
static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
int *sizeArgPtr)
{
int size =
pcm_sizeOfOutputBufferForAudioFormatConversion(&
(audioOutput->
inAudioFormat),
*sizeArgPtr,
&(audioOutput->outAudioFormat));
int size = pcm_sizeOfConvBuffer(&(audioOutput->inAudioFormat),
*sizeArgPtr,
&(audioOutput->outAudioFormat));
if (size > audioOutput->convBufferLen) {
audioOutput->convBuffer =
......@@ -202,11 +202,12 @@ static void convertAudioFormat(AudioOutput * audioOutput, char **chunkArgPtr,
audioOutput->convBufferLen = size;
}
pcm_convertAudioFormat(&(audioOutput->inAudioFormat), *chunkArgPtr,
*sizeArgPtr, &(audioOutput->outAudioFormat),
audioOutput->convBuffer);
*sizeArgPtr = pcm_convertAudioFormat(&(audioOutput->inAudioFormat),
*chunkArgPtr, *sizeArgPtr,
&(audioOutput->outAudioFormat),
audioOutput->convBuffer,
&audioOutput->convState);
*sizeArgPtr = size;
*chunkArgPtr = audioOutput->convBuffer;
}
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -21,24 +21,14 @@
#include "../config.h"
#include "pcm_utils.h"
#include "mpd_types.h"
#include "audio.h"
#include "tag.h"
#include "conf.h"
#include "utils.h"
#define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) \
AudioOutputPlugin plugin = { \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
NULL \
};
#define DISABLED_AUDIO_OUTPUT_PLUGIN(plugin) AudioOutputPlugin plugin;
typedef struct _AudioOutput AudioOutput;
......@@ -77,6 +67,7 @@ struct _AudioOutput {
AudioFormat inAudioFormat;
AudioFormat outAudioFormat;
AudioFormat reqAudioFormat;
ConvState convState;
char *convBuffer;
int convBufferLen;
int sameInAndOutFormats;
......@@ -113,4 +104,14 @@ int keepAudioOutputAlive(AudioOutput * audioOutput, int ms);
void sendMetadataToAudioOutput(AudioOutput * audioOutput, MpdTag * tag);
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
/* 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 program is free software; you can redistribute it and/or modify
......@@ -34,11 +34,8 @@
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <alsa/asoundlib.h>
......@@ -88,8 +85,7 @@ static int alsa_initDriver(AudioOutput * audioOutput, ConfigParam * param)
ad->device = bp ? xstrdup(bp->value) : xstrdup("default");
if ((bp = getBlockParam(param, "use_mmap")) &&
(!strcasecmp(bp->value, "yes") ||
!strcasecmp(bp->value, "true")))
!strcasecmp(bp->value, "yes"))
ad->useMmap = 1;
if ((bp = getBlockParam(param, "buffer_time")))
ad->buffer_time = atoi(bp->value);
......@@ -210,7 +206,7 @@ configure_hw:
err = snd_pcm_hw_params_set_format(ad->pcmHandle, hwparams, bitformat);
if (err < 0) {
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;
}
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -24,12 +24,10 @@
#include "../log.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <ao/ao.h>
static int driverInitCount = 0;
static int driverInitCount;
typedef struct _AoData {
int writeSize;
......@@ -77,9 +75,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
if ((blockParam = getBlockParam(param, "write_size"))) {
ad->writeSize = strtol(blockParam->value, &test, 10);
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);
exit(EXIT_FAILURE);
}
} else
ad->writeSize = 1024;
......@@ -94,16 +91,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
if (!blockParam || 0 == strcmp(blockParam->value, "default")) {
ad->driverId = ao_default_driver_id();
} 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);
exit(EXIT_FAILURE);
}
if ((ai = ao_driver_info(ad->driverId)) == NULL) {
ERROR("problems getting driver info for device defined at "
"line %i\n", param->line);
ERROR("you may not have permission to the audio device\n");
exit(EXIT_FAILURE);
FATAL("problems getting driver info for device defined at line %i\n"
"you may not have permission to the audio device\n", param->line);
}
DEBUG("using ao driver \"%s\" for \"%s\"\n", ai->short_name,
......@@ -122,11 +116,8 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
while (n1) {
stk2 = NULL;
key = strtok_r(n1, "=", &stk2);
if (!key) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
if (!key)
FATAL("problems parsing options \"%s\"\n", n1);
/*found = 0;
for(i=0;i<ai->option_count;i++) {
if(strcmp(ai->options[i],key)==0) {
......@@ -135,17 +126,13 @@ static int audioOutputAo_initDriver(AudioOutput * audioOutput,
}
}
if(!found) {
ERROR("\"%s\" is not an option for "
FATAL("\"%s\" is not an option for "
"\"%s\" ao driver\n",key,
ai->short_name);
exit(EXIT_FAILURE);
} */
value = strtok_r(NULL, "", &stk2);
if (!value) {
ERROR("problems parsing "
"ao_driver_options \"%s\"\n", n1);
exit(EXIT_FAILURE);
}
if (!value)
FATAL("problems parsing options \"%s\"\n", n1);
ao_append_option(&ad->options, key, value);
n1 = strtok_r(NULL, ";", &stk1);
}
......
/* 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
*
* Media MVP audio output based on code from MVPMC project:
......@@ -27,11 +27,8 @@
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
......
/* 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
*
* 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>
*
* This program is free software; you can redistribute it and/or modify
......@@ -25,14 +25,10 @@
#ifdef HAVE_OSS
#include "../utils.h"
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/stat.h>
......@@ -363,7 +359,7 @@ static int oss_open_default(AudioOutput *ao, ConfigParam *param, OssData *od)
}
if (param)
ERROR("Error trying to open specified OSS device"
ERROR("error trying to open specified OSS device"
" at line %i\n", param->line);
else
ERROR("error trying to open default OSS device\n");
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -25,7 +25,6 @@
#include <pthread.h>
#include "../log.h"
#include "../utils.h"
typedef struct _OsxData {
AudioUnit au;
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -24,12 +24,9 @@
#include "../conf.h"
#include "../log.h"
#include "../sig_handlers.h"
#include "../pcm_utils.h"
#include <string.h>
#include <assert.h>
#include <signal.h>
#include <time.h>
#include <shout/shout.h>
......@@ -37,7 +34,7 @@
#define CONN_ATTEMPT_INTERVAL 60
static int shoutInitCount = 0;
static int shoutInitCount;
/* lots of this code blatantly stolent from bossogg/bossao2 */
......@@ -67,6 +64,7 @@ typedef struct _ShoutData {
int connAttempts;
time_t lastAttempt;
int last_err;
/* just a pointer to audioOutput->outAudioFormat */
AudioFormat *audioFormat;
......@@ -85,6 +83,7 @@ static ShoutData *newShoutData(void)
ret->connAttempts = 0;
ret->lastAttempt = 0;
ret->audioFormat = NULL;
ret->last_err = SHOUTERR_UNCONNECTED;
return ret;
}
......@@ -101,10 +100,9 @@ static void freeShoutData(ShoutData * sd)
#define checkBlockParam(name) { \
blockParam = getBlockParam(param, name); \
if(!blockParam) { \
ERROR("no \"%s\" defined for shout device defined at line " \
if (!blockParam) { \
FATAL("no \"%s\" defined for shout device defined at line " \
"%i\n", name, param->line); \
exit(EXIT_FAILURE); \
} \
}
......@@ -119,7 +117,7 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
char *user;
char *name;
BlockParam *blockParam;
unsigned int public;
unsigned int public = 0;
sd = newShoutData();
......@@ -139,9 +137,8 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
port = strtol(blockParam->value, &test, 10);
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);
exit(EXIT_FAILURE);
}
checkBlockParam("password");
......@@ -152,17 +149,15 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
blockParam = getBlockParam(param, "public");
if (blockParam) {
if (0 == strcmp(blockParam->value, "yes"))
if (0 == strcmp(blockParam->value, "yes")) {
public = 1;
else if (0 == strcmp(blockParam->value, "no"))
} else if (0 == strcmp(blockParam->value, "no")) {
public = 0;
else {
ERROR("public \"%s\" is not \"yes\" or \"no\" at line "
} else {
FATAL("public \"%s\" is not \"yes\" or \"no\" at line "
"%i\n", param->value, param->line);
exit(EXIT_FAILURE);
}
} else
public = 0;
}
blockParam = getBlockParam(param, "user");
if (blockParam)
......@@ -178,35 +173,31 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
sd->quality = strtod(blockParam->value, &test);
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,
blockParam->line);
exit(EXIT_FAILURE);
}
blockParam = getBlockParam(param, "bitrate");
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,
blockParam->line);
exit(EXIT_FAILURE);
}
} else {
blockParam = getBlockParam(param, "bitrate");
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);
exit(EXIT_FAILURE);
}
sd->bitrate = strtol(blockParam->value, &test, 10);
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);
exit(EXIT_FAILURE);
}
}
......@@ -220,30 +211,28 @@ static int myShout_initDriver(AudioOutput * audioOutput, ConfigParam * param)
shout_set_name(sd->shoutConn, name) != SHOUTERR_SUCCESS ||
shout_set_user(sd->shoutConn, user) != 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)
!= SHOUTERR_SUCCESS ||
shout_set_protocol(sd->shoutConn, SHOUT_PROTOCOL_HTTP)
!= 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));
exit(EXIT_FAILURE);
}
/* optional paramters */
blockParam = getBlockParam(param, "genre");
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));
exit(EXIT_FAILURE);
}
blockParam = getBlockParam(param, "description");
if (blockParam && shout_set_description(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));
exit(EXIT_FAILURE);
}
{
......@@ -358,6 +347,7 @@ static void myShout_closeShoutConn(ShoutData * sd)
}
}
sd->last_err = SHOUTERR_UNCONNECTED;
sd->opened = 0;
}
......@@ -460,9 +450,19 @@ static int myShout_openShoutConn(AudioOutput * audioOutput)
sd->connAttempts++;
sd->lastAttempt = t;
if (shout_open(sd->shoutConn) != SHOUTERR_SUCCESS) {
if (sd->last_err == SHOUTERR_UNCONNECTED)
sd->last_err = shout_open(sd->shoutConn);
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 "
"(attempt %i): %s\n",
shout_get_host(sd->shoutConn),
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -27,18 +27,18 @@
#ifdef HAVE_ICONV
#include <iconv.h>
iconv_t char_conv_iconv;
static iconv_t char_conv_iconv;
#endif
char *char_conv_to = NULL;
char *char_conv_from = NULL;
mpd_sint8 char_conv_same = 0;
mpd_sint8 char_conv_use_iconv = 0;
static char *char_conv_to;
static char *char_conv_from;
static mpd_sint8 char_conv_same;
static mpd_sint8 char_conv_use_iconv;
/* 1 is to use latin1ToUtf8
0 is not to use latin1/utf8 converter
-1 is to use utf8ToLatin1*/
mpd_sint8 char_conv_latin1ToUtf8 = 0;
static mpd_sint8 char_conv_latin1ToUtf8;
#define BUFFER_SIZE 1024
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -28,9 +28,9 @@
#include "permission.h"
#include "buffer2array.h"
#include "log.h"
#include "dbUtils.h"
#include "tag.h"
#include "utils.h"
#include "storedPlaylist.h"
#include <assert.h>
#include <stdarg.h>
......@@ -92,6 +92,15 @@
#define COMMAND_DEVICES "outputs"
#define COMMAND_COMMANDS "commands"
#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_STATE "state"
......@@ -132,8 +141,8 @@ struct _CommandEntry {
CommandListHandlerFunction listHandler;
};
static char *current_command = NULL;
static int command_listNum = 0;
static char *current_command;
static int command_listNum;
static CommandEntry *getCommandEntryFromString(char *string, int *permission);
......@@ -174,6 +183,12 @@ static int handleUrlHandlers(int fd, int *permission, int argc, char *argv[])
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[])
{
int song = -1;
......@@ -388,17 +403,18 @@ static int handleListPlaylistInfo(int fd, int *permission,
static int handleLsInfo(int fd, int *permission, int argc, char *argv[])
{
if (argc == 1) {
if (printDirectoryInfo(fd, NULL) < 0)
return -1;
else
return lsPlaylists(fd, "");
} else {
if (printDirectoryInfo(fd, argv[1]) < 0)
return -1;
else
return lsPlaylists(fd, argv[1]);
}
char *path = "";
if (argc == 2)
path = argv[1];
if (printDirectoryInfo(fd, path) < 0)
return -1;
if (isRootDirectory(path))
return lsPlaylists(fd, path);
return 0;
}
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]);
}
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,
int argc, char *argv[])
{
......@@ -508,13 +529,109 @@ static int handleSearch(int fd, int *permission, int argc, char *argv[])
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,
int *permission,
int argc,
char *argv[],
struct strnode *cmdnode, CommandEntry * cmd)
{
static List *pathList = NULL;
static List *pathList;
CommandEntry *nextCmd = NULL;
struct strnode *next = cmdnode->next;
......@@ -646,6 +763,12 @@ static int handleList(int fd, int *permission, int argc, char *argv[])
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 */
if (argc == 3) {
if (tagType != TAG_ITEM_ALBUM) {
......@@ -917,6 +1040,22 @@ static int handleNotcommands(int fd, int *permission, int argc, char *argv[])
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)
{
commandList = makeList(free, 1);
......@@ -976,6 +1115,15 @@ void initCommands(void)
addCommand(COMMAND_DEVICES, PERMISSION_READ, 0, 0, handleDevices, NULL);
addCommand(COMMAND_COMMANDS, PERMISSION_NONE, 0, 0, handleCommands, 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);
}
......@@ -1134,15 +1282,18 @@ mpd_fprintf_ void commandError(int fd, int error, const char *fmt, ...)
va_list args;
va_start(args, fmt);
if (current_command) {
if (current_command && fd != STDERR_FILENO) {
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;
} else
} else {
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);
fdprintf(fd, "\n");
}
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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
*
* Compressor logic by
......@@ -39,7 +39,7 @@ static int screen;
static GC blackGC, whiteGC, blueGC, yellowGC, dkyellowGC, redGC;
#endif
static int *peaks = NULL;
static int *peaks;
static int gainCurrent, gainTarget;
static struct {
......@@ -52,13 +52,13 @@ static struct {
} prefs;
#ifdef USE_X
static int mon_init = 0;
static int mon_init;
#endif
void CompressCfg(int show_mon, int anticlip, int target, int gainmax,
int gainsmooth, int buckets)
{
static int lastsize = 0;
static int lastsize;
prefs.show_mon = show_mon;
prefs.anticlip = anticlip;
......@@ -179,9 +179,9 @@ void CompressDo(void *data, unsigned int length)
int gr, gf, gn;
static int pn = -1;
#ifdef STATS
static int clip = 0;
static int clip;
#endif
static int clipped = 0;
static int clipped;
if (!peaks)
return;
......
/* 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
*
* interface to audio compression
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -48,7 +48,7 @@ typedef struct _configEntry {
List *configParamList;
} ConfigEntry;
static List *configEntriesList = NULL;
static List *configEntriesList;
static ConfigParam *newConfigParam(char *value, int line)
{
......@@ -115,10 +115,8 @@ static void registerConfigParam(char *name, int repeatable, int block)
{
ConfigEntry *entry;
if (findInList(configEntriesList, name, NULL)) {
ERROR("config parameter \"%s\" already registered\n", name);
exit(EXIT_FAILURE);
}
if (findInList(configEntriesList, name, NULL))
FATAL("config parameter \"%s\" already registered\n", name);
entry = newConfigEntry(repeatable, block);
......@@ -146,6 +144,7 @@ void initConf(void)
registerConfigParam(CONF_BIND_TO_ADDRESS, 1, 0);
registerConfigParam(CONF_PORT, 0, 0);
registerConfigParam(CONF_LOG_LEVEL, 0, 0);
registerConfigParam(CONF_ZEROCONF_NAME, 0, 0);
registerConfigParam(CONF_PASSWORD, 1, 0);
registerConfigParam(CONF_DEFAULT_PERMS, 0, 0);
registerConfigParam(CONF_AUDIO_OUTPUT, 1, 1);
......@@ -156,6 +155,7 @@ void initConf(void)
registerConfigParam(CONF_REPLAYGAIN, 0, 0);
registerConfigParam(CONF_REPLAYGAIN_PREAMP, 0, 0);
registerConfigParam(CONF_VOLUME_NORMALIZATION, 0, 0);
registerConfigParam(CONF_SAMPLERATE_CONVERTER, 0, 0);
registerConfigParam(CONF_AUDIO_BUFFER_SIZE, 0, 0);
registerConfigParam(CONF_BUFFER_BEFORE_PLAY, 0, 0);
registerConfigParam(CONF_HTTP_BUFFER_SIZE, 0, 0);
......@@ -173,6 +173,7 @@ void initConf(void)
registerConfigParam(CONF_ID3V1_ENCODING, 0, 0);
registerConfigParam(CONF_METADATA_TO_USE, 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,
......@@ -222,19 +223,17 @@ static ConfigParam *readConfigBlock(FILE * fp, int *count, char *string)
}
if (2 != argsMinusComment) {
ERROR("improperly formatted config file at line %i:"
FATAL("improperly formatted config file at line %i:"
" %s\n", *count, string);
exit(EXIT_FAILURE);
}
if (0 == strcmp(array[0], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[1], CONF_BLOCK_BEGIN) ||
0 == strcmp(array[0], CONF_BLOCK_END) ||
0 == strcmp(array[1], CONF_BLOCK_END)) {
ERROR("improperly formatted config file at line %i:"
" %s\n", *count, string);
ERROR("in block beginning at line %i\n", ret->line);
exit(EXIT_FAILURE);
FATAL("improperly formatted config file at line %i: %s\n"
"in block beginning at line %i\n",
*count, string, ret->line);;
}
addBlockParam(ret, array[0], array[1], *count);
......@@ -256,9 +255,8 @@ void readConf(char *file)
ConfigParam *param;
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));
exit(EXIT_FAILURE);
}
while (myFgets(string, MAX_STRING_SIZE, fp)) {
......@@ -279,15 +277,13 @@ void readConf(char *file)
}
if (2 != argsMinusComment) {
ERROR("improperly formatted config file at line %i:"
FATAL("improperly formatted config file at line %i:"
" %s\n", count, string);
exit(EXIT_FAILURE);
}
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);
exit(EXIT_FAILURE);
}
entry = (ConfigEntry *) voidPtr;
......@@ -295,18 +291,15 @@ void readConf(char *file)
if (!(entry->mask & CONF_REPEATABLE_MASK) &&
entry->configParamList->numberOfNodes) {
param = entry->configParamList->firstNode->data;
ERROR
("config parameter \"%s\" is first defined on line "
FATAL("config parameter \"%s\" is first defined on line "
"%i and redefined on line %i\n", array[0],
param->line, count);
exit(EXIT_FAILURE);
}
if (entry->mask & CONF_BLOCK_MASK) {
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);
exit(EXIT_FAILURE);
}
param = readConfigBlock(fp, &count, string);
} else
......@@ -397,10 +390,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
ConfigParam *param = getConfigParam(name);
char *path;
if (!param && force) {
ERROR("config parameter \"%s\" not found\n", name);
exit(EXIT_FAILURE);
}
if (!param && force)
FATAL("config parameter \"%s\" not found\n", name);
if (!param)
return NULL;
......@@ -408,9 +399,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
path = param->value;
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);
exit(EXIT_FAILURE);
}
/* Parse ~ in path */
else if (path[0] == '~') {
......@@ -423,17 +413,15 @@ ConfigParam *parseConfigFilePath(char *name, int force)
if (userParam) {
pwd = getpwnam(userParam->value);
if (!pwd) {
ERROR("no such user %s at line %i\n",
FATAL("no such user %s at line %i\n",
userParam->value,
userParam->line);
exit(EXIT_FAILURE);
}
} else {
uid_t uid = geteuid();
if ((pwd = getpwuid(uid)) == NULL) {
ERROR("problems getting passwd entry "
FATAL("problems getting passwd entry "
"for current user\n");
exit(EXIT_FAILURE);
}
}
} else {
......@@ -445,9 +433,8 @@ ConfigParam *parseConfigFilePath(char *name, int force)
*ch = '\0';
pos += ch - path - 1;
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);
exit(EXIT_FAILURE);
}
if (foundSlash)
*ch = '/';
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -32,6 +32,7 @@
#define CONF_BIND_TO_ADDRESS "bind_to_address"
#define CONF_PORT "port"
#define CONF_LOG_LEVEL "log_level"
#define CONF_ZEROCONF_NAME "zeroconf_name"
#define CONF_PASSWORD "password"
#define CONF_DEFAULT_PERMS "default_permissions"
#define CONF_AUDIO_OUTPUT "audio_output"
......@@ -42,6 +43,7 @@
#define CONF_REPLAYGAIN "replaygain"
#define CONF_REPLAYGAIN_PREAMP "replaygain_preamp"
#define CONF_VOLUME_NORMALIZATION "volume_normalization"
#define CONF_SAMPLERATE_CONVERTER "samplerate_converter"
#define CONF_AUDIO_BUFFER_SIZE "audio_buffer_size"
#define CONF_BUFFER_BEFORE_PLAY "buffer_before_play"
#define CONF_HTTP_BUFFER_SIZE "http_buffer_size"
......@@ -59,6 +61,7 @@
#define CONF_ID3V1_ENCODING "id3v1_encoding"
#define CONF_METADATA_TO_USE "metadata_to_use"
#define CONF_SAVE_ABSOLUTE_PATHS "save_absolute_paths_in_playlists"
#define CONF_GAPLESS_MP3_PLAYBACK "gapless_mp3_playback"
typedef struct _BlockParam {
char *name;
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -22,14 +22,11 @@
#include "myfprintf.h"
#include "utils.h"
#include "playlist.h"
#include "song.h"
#include "tag.h"
#include "tagTracker.h"
#include "log.h"
#define LOCATE_TAG_FILE_TYPE TAG_NUM_OF_ITEM_TYPES+10
#define LOCATE_TAG_FILE_KEY "filename"
#define LOCATE_TAG_ANY_TYPE TAG_NUM_OF_ITEM_TYPES+20
#define LOCATE_TAG_ANY_KEY "any"
#include "storedPlaylist.h"
typedef struct _ListCommandItem {
mpd_sint8 tagType;
......@@ -42,97 +39,11 @@ typedef struct _LocateTagItemArray {
LocateTagItem *items;
} LocateTagItemArray;
int getLocateTagItemType(char *str)
{
int i;
if (0 == strcasecmp(str, LOCATE_TAG_FILE_KEY)) {
return LOCATE_TAG_FILE_TYPE;
}
if (0 == strcasecmp(str, LOCATE_TAG_ANY_KEY)) {
return LOCATE_TAG_ANY_TYPE;
}
for (i = 0; i < TAG_NUM_OF_ITEM_TYPES; i++) {
if (0 == strcasecmp(str, mpdTagItemKeys[i]))
return i;
}
return -1;
}
static int initLocateTagItem(LocateTagItem * item, char *typeStr, char *needle)
{
item->tagType = getLocateTagItemType(typeStr);
if (item->tagType < 0)
return -1;
item->needle = 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);
}
typedef struct _SearchStats {
LocateTagItemArray locateArray;
int numberOfSongs;
unsigned long playTime;
} SearchStats;
static int countSongsInDirectory(int fd, Directory * directory, void *data)
{
......@@ -158,53 +69,12 @@ static int printSongInDirectory(int fd, Song * song, void *data)
return 0;
}
static int strstrSearchTag(Song * song, int type, char *str)
{
int i;
char *dup;
int ret = 0;
if (type == LOCATE_TAG_FILE_TYPE || type == LOCATE_TAG_ANY_TYPE) {
dup = strDupToUpper(getSongUrl(song));
if (strstr(dup, str))
ret = 1;
free(dup);
if (ret == 1 || type == LOCATE_TAG_FILE_TYPE) {
return ret;
}
}
if (!song->tag)
return 0;
for (i = 0; i < song->tag->numOfItems && !ret; i++) {
if (type != LOCATE_TAG_ANY_TYPE &&
song->tag->items[i].type != type) {
continue;
}
dup = strDupToUpper(song->tag->items[i].value);
if (strstr(dup, str))
ret = 1;
free(dup);
}
return ret;
}
static int searchInDirectory(int fd, Song * song, void *data)
{
LocateTagItemArray *array = data;
int i;
for (i = 0; i < array->numItems; i++) {
if (!strstrSearchTag(song, array->items[i].tagType,
array->items[i].needle)) {
return 0;
}
}
printSongInfo(fd, song);
if (strstrSearchTags(song, array->numItems, array->items))
printSongInfo(fd, song);
return 0;
}
......@@ -237,54 +107,62 @@ int searchForSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
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 (0 == strcmp(str, getSongUrl(song)))
return 1;
}
if (tagItemsFoundAndMatches(song, array->numItems, array->items))
printSongInfo(fd, song);
if (!song->tag)
return 0;
return 0;
}
for (i = 0; i < song->tag->numOfItems; i++) {
if (song->tag->items[i].type != type)
continue;
int findSongsIn(int fd, char *name, int numItems, LocateTagItem * items)
{
LocateTagItemArray array;
if (0 == strcmp(str, song->tag->items[i].value))
return 1;
}
array.numItems = numItems;
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;
int i;
fdprintf(fd, "songs: %i\n", stats->numberOfSongs);
fdprintf(fd, "playtime: %li\n", stats->playTime);
}
for (i = 0; i < array->numItems; i++) {
if (!tagItemFoundAndMatches(song, array->items[i].tagType,
array->items[i].needle)) {
return 0;
}
}
static int searchStatsInDirectory(int fd, Song * song, void *data)
{
SearchStats *stats = data;
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;
}
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;
array.items = items;
stats.locateArray.numItems = numItems;
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)
......@@ -298,11 +176,24 @@ static int directoryAddSongToPlaylist(int fd, Song * song, void *data)
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)
{
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)
{
return printSongInfo(fd, song);
......@@ -384,17 +275,12 @@ static void visitTag(int fd, Song * song, int tagType)
static int listUniqueTagsInDirectory(int fd, Song * song, void *data)
{
ListCommandItem *item = data;
int i;
for (i = 0; i < item->numConditionals; i++) {
if (!tagItemFoundAndMatches(song, item->conditionals[i].tagType,
item->conditionals[i].needle)) {
return 0;
}
if (tagItemsFoundAndMatches(song, item->numConditionals,
item->conditionals)) {
visitTag(fd, song, item->tagType);
}
visitTag(fd, song, item->tagType);
return 0;
}
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -21,39 +21,24 @@
#include <stdio.h>
#include "tag.h"
/* struct used for search, find, list queries */
typedef struct _LocateTagItem {
mpd_sint8 tagType;
/* what we are looking for */
char *needle;
} LocateTagItem;
int getLocateTagItemType(char *str);
/* returns NULL if not a known type */
LocateTagItem *newLocateTagItem(char *typeString, char *needle);
/* return number of items or -1 on error */
int newLocateTagItemArrayFromArgArray(char *argArray[], int numArgs,
LocateTagItem ** arrayRet);
void freeLocateTagItemArray(int count, LocateTagItem * array);
void freeLocateTagItem(LocateTagItem * item);
#include "locate.h"
int printAllIn(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 searchForSongsIn(int fd, char *name, int numItems,
LocateTagItem * items);
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);
unsigned long sumSongTimesIn(int fd, char *name);
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -37,7 +37,7 @@
#include <unistd.h>
#include <string.h>
static int decode_pid = 0;
static int decode_pid;
void decodeSigHandler(int sig, siginfo_t * si, void *v)
{
......@@ -76,7 +76,6 @@ static void stopDecode(DecoderControl * dc)
static void quitDecode(PlayerControl * pc, DecoderControl * dc)
{
stopDecode(dc);
pc->metadataState = PLAYER_METADATA_STATE_READ;
pc->state = PLAYER_STATE_STOP;
dc->seek = 0;
pc->play = 0;
......@@ -221,20 +220,20 @@ static int decodeSeek(PlayerControl * pc, DecoderControl * dc,
} \
if(pc->pause) { \
pause = !pause; \
if(pause) pc->state = PLAYER_STATE_PAUSE; \
if (pause) pc->state = PLAYER_STATE_PAUSE; \
else { \
if(openAudioDevice(NULL)<0) { \
if (openAudioDevice(NULL) >= 0) pc->state = PLAYER_STATE_PLAY; \
else { \
pathcpy_trunc(pc->erroredUrl, pc->utf8url); \
pc->error = PLAYER_ERROR_AUDIO; \
ERROR("problems opening audio device while playing \"%s\"\n", pc->utf8url); \
quitDecode(pc,dc); \
return; \
pause = -1; \
} \
pc->state = PLAYER_STATE_PLAY; \
} \
pc->pause = 0; \
kill(getppid(),SIGUSR1); \
if(pause) { \
kill(getppid(), SIGUSR1); \
if (pause == -1) pause = 1; \
else if (pause) { \
dropBufferedAudio(); \
closeAudioDevice(); \
} \
......@@ -285,7 +284,6 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
return;
}
dc->seekable = inStream.seekable;
dc->state = DECODE_STATE_START;
dc->start = 0;
......@@ -295,6 +293,9 @@ static void decodeStart(PlayerControl * pc, OutputBuffer * cb,
my_usleep(1000);
}
/* for http streams, seekable is determined in bufferInputStream */
dc->seekable = inStream.seekable;
if (dc->stop) {
dc->state = DECODE_STATE_STOP;
dc->stop = 0;
......@@ -480,10 +481,10 @@ static void advanceOutputBufferTo(OutputBuffer * cb, PlayerControl * pc,
while (cb->begin != to) {
handleMetadata(cb, pc, previous, currentChunkSent,
currentChunk);
cb->begin++;
if (cb->begin >= buffered_chunks) {
if (cb->begin + 1 >= buffered_chunks) {
cb->begin = 0;
}
else cb->begin++;
}
}
......@@ -516,7 +517,8 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
pc->play = 0;
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 &&
dc->state != DECODE_STATE_STOP) {
processDecodeInput();
......@@ -617,10 +619,10 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
cb->begin = 0;
} else
cb->begin++;
} else if (next == cb->begin) {
} else if (cb->begin != end && cb->begin == next) {
if (doCrossFade == 1 && nextChunk >= 0) {
nextChunk = cb->begin + crossFadeChunks;
test = cb->end;
test = end;
if (end < cb->begin)
test += buffered_chunks;
if (nextChunk < test) {
......@@ -663,6 +665,7 @@ static void decodeParent(PlayerControl * pc, DecoderControl * dc, OutputBuffer *
quit = 1;
break;
} else {
/*DEBUG("waiting for decoded audio, play silence\n");*/
if (playAudio(silence, CHUNK_SIZE) < 0)
quit = 1;
}
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -59,15 +59,15 @@
#define DIRECTORY_RETURN_UPDATE 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();
......@@ -543,7 +543,7 @@ static int updatePath(char *utf8path)
free(path);
return 0;
}
/* if updateDirectory fials, means we should delete it */
/* if updateDirectory fails, means we should delete it */
else {
LOG("removing directory: %s\n", path);
deleteFromList(parentDirectory->subDirectories,
......@@ -573,7 +573,7 @@ static int updatePath(char *utf8path)
return 1;
}
}
/* if updateDirectory fials, means we should delete it */
/* if updateDirectory fails, means we should delete it */
else {
removeSongFromDirectory(parentDirectory, shortname);
ret = 1;
......@@ -835,13 +835,21 @@ static Directory *findSubDirectory(Directory * directory, char *name)
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,
char **shortname)
{
Directory *subDirectory;
int len;
if (name == NULL || name[0] == '\0' || strcmp(name, "/") == 0) {
if (isRootDirectory(name)) {
return directory;
}
......@@ -943,23 +951,18 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
&& 0 != strncmp(DIRECTORY_END, buffer, strlen(DIRECTORY_END))) {
if (0 == strncmp(DIRECTORY_DIR, buffer, strlen(DIRECTORY_DIR))) {
key = xstrdup(&(buffer[strlen(DIRECTORY_DIR)]));
if (!myFgets(buffer, bufferSize, fp)) {
ERROR("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
/* for compatibility with db's prior to 0.11 */
if (0 == strncmp(DIRECTORY_MTIME, buffer,
strlen(DIRECTORY_MTIME))) {
if (!myFgets(buffer, bufferSize, fp)) {
ERROR("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
}
if (strncmp
(DIRECTORY_BEGIN, buffer,
strlen(DIRECTORY_BEGIN))) {
ERROR("Error reading db at line: %s\n", buffer);
exit(EXIT_FAILURE);
FATAL("Error reading db at line: %s\n", buffer);
}
name = xstrdup(&(buffer[strlen(DIRECTORY_BEGIN)]));
......@@ -993,8 +996,7 @@ static void readDirectoryInfo(FILE * fp, Directory * directory)
} else if (0 == strncmp(SONG_BEGIN, buffer, strlen(SONG_BEGIN))) {
readSongInfoIntoList(fp, directory->songs, directory);
} else {
ERROR("Unknown line in db: %s\n", buffer);
exit(EXIT_FAILURE);
FATAL("Unknown line in db: %s\n", buffer);
}
}
......@@ -1091,6 +1093,7 @@ int writeDirectoryDB(void)
{
FILE *fp;
char *dbFile = getDbFile();
struct stat st;
DEBUG("removing empty directories from DB\n");
deleteEmptyDirectoriesInDirectory(mp3rootDirectory);
......@@ -1101,7 +1104,7 @@ int writeDirectoryDB(void)
DEBUG("writing DB\n");
while (!(fp = fopen(dbFile, "w")) && errno == EINTR) ;
while (!(fp = fopen(dbFile, "w")) && errno == EINTR);
if (!fp) {
ERROR("unable to write to db file \"%s\": %s\n",
dbFile, strerror(errno));
......@@ -1116,7 +1119,10 @@ int writeDirectoryDB(void)
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;
}
......@@ -1131,7 +1137,7 @@ int readDirectoryDB(void)
mp3rootDirectory = newDirectory(NULL, NULL);
while (!(fp = fopen(dbFile, "r")) && errno == EINTR) ;
if (fp == NULL) {
ERROR("unable open db file \"%s\": %s\n",
ERROR("unable to open db file \"%s\": %s\n",
dbFile, strerror(errno));
return -1;
}
......@@ -1143,21 +1149,16 @@ int readDirectoryDB(void)
int foundFsCharset = 0;
int foundVersion = 0;
if (!myFgets(buffer, bufferSize, fp)) {
ERROR("Error reading db, fgets\n");
exit(EXIT_FAILURE);
}
if (!myFgets(buffer, bufferSize, fp))
FATAL("Error reading db, fgets\n");
if (0 == strcmp(DIRECTORY_INFO_BEGIN, buffer)) {
while (myFgets(buffer, bufferSize, fp) &&
0 != strcmp(DIRECTORY_INFO_END, buffer)) {
if (0 == strncmp(DIRECTORY_MPD_VERSION, buffer,
strlen(DIRECTORY_MPD_VERSION)))
{
if (foundVersion) {
ERROR("already found "
"version in db\n");
exit(EXIT_FAILURE);
}
if (foundVersion)
FATAL("already found version in db\n");
foundVersion = 1;
} else if (0 ==
strncmp(DIRECTORY_FS_CHARSET, buffer,
......@@ -1166,20 +1167,13 @@ int readDirectoryDB(void)
char *fsCharset;
char *tempCharset;
if (foundFsCharset) {
WARNING("already found "
"fs charset in db\n");
exit(EXIT_FAILURE);
}
if (foundFsCharset)
FATAL("already found fs charset in db\n");
foundFsCharset = 1;
fsCharset =
&(buffer
[strlen(DIRECTORY_FS_CHARSET)]);
if ((tempCharset =
getConfigParamValue
(CONF_FS_CHARSET))
fsCharset = &(buffer[strlen(DIRECTORY_FS_CHARSET)]);
if ((tempCharset = getConfigParamValue(CONF_FS_CHARSET))
&& strcmp(fsCharset, tempCharset)) {
WARNING("Using \"%s\" for the "
"filesystem charset "
......@@ -1190,10 +1184,8 @@ int readDirectoryDB(void)
setFsCharset(fsCharset);
}
} else {
ERROR
("directory: unknown line in db info: %s\n",
FATAL("directory: unknown line in db info: %s\n",
buffer);
exit(EXIT_FAILURE);
}
}
} else {
......@@ -1225,14 +1217,12 @@ void updateMp3Directory(void)
/* nothing updated */
return;
case 1:
if (writeDirectoryDB() < 0) {
if (writeDirectoryDB() < 0)
exit(EXIT_FAILURE);
}
break;
default:
/* something was updated and db should be written */
ERROR("problems updating music db\n");
exit(EXIT_FAILURE);
FATAL("problems updating music db\n");
}
return;
......@@ -1311,16 +1301,11 @@ static void freeAllDirectoryStats(Directory * directory)
void initMp3Directory(void)
{
struct stat st;
mp3rootDirectory = newDirectory(NULL, NULL);
exploreDirectory(mp3rootDirectory);
freeAllDirectoryStats(mp3rootDirectory);
stats.numberOfSongs = countSongsIn(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,
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -51,6 +51,8 @@ void initMp3Directory(void);
void closeMp3Directory(void);
int isRootDirectory(char *name);
int printDirectoryInfo(int fd, char *dirname);
int checkDirectoryDB(void);
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -24,7 +24,7 @@
#include <stdlib.h>
#include <string.h>
static List *inputPlugin_list = NULL;
static List *inputPlugin_list;
void loadInputPlugin(InputPlugin * inputPlugin)
{
......@@ -59,7 +59,7 @@ static int stringFoundInStringArray(char **array, char *suffix)
InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
{
static ListNode *pos = NULL;
static ListNode *pos;
ListNode *node;
InputPlugin *plugin;
......@@ -88,7 +88,7 @@ InputPlugin *getInputPluginFromSuffix(char *suffix, unsigned int next)
InputPlugin *getInputPluginFromMimeType(char *mimeType, unsigned int next)
{
static ListNode *pos = NULL;
static ListNode *pos;
ListNode *node;
InputPlugin *plugin;
......@@ -137,16 +137,6 @@ void printAllInputPluginSuffixes(FILE * 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)
{
inputPlugin_list = makeList(NULL, 1);
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -96,4 +96,14 @@ void initInputPlugins(void);
/* this is where we "unload" all the "plugins" */
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
/* 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
*
* Common data structures and functions used by FLAC and OggFLAC
......
/* 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
*
* Common data structures and functions used by FLAC and OggFLAC
......@@ -30,7 +30,116 @@
#include "../inputStream.h"
#include "../outputBuffer.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>
#define FLAC_CHUNK_SIZE 4080
......
/* 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
*
* Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
......
/* 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
*
* Common functions used for Ogg data streams (Ogg-Vorbis and OggFLAC)
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -237,7 +237,7 @@ static float getAacFloatTotalTime(char *file)
size_t fileread, tagsize;
faacDecHandle decoder;
faacDecConfigurationPtr config;
unsigned int sampleRate;
unsigned long sampleRate;
unsigned char channels;
InputStream inStream;
long bread;
......@@ -293,7 +293,7 @@ static int aac_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
faacDecFrameInfo frameInfo;
faacDecConfigurationPtr config;
long bread;
unsigned int sampleRate;
unsigned long sampleRate;
unsigned char channels;
int eof = 0;
unsigned int sampleCount;
......@@ -470,17 +470,6 @@ InputPlugin aacPlugin = {
#else
InputPlugin aacPlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
InputPlugin aacPlugin;
#endif /* HAVE_FAAD */
/* 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
*
* libaudiofile (wave) support added by Eric Wong <normalperson@yhbt.net>
......@@ -183,17 +183,6 @@ InputPlugin audiofilePlugin = {
#else
InputPlugin audiofilePlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
InputPlugin audiofilePlugin;
#endif /* HAVE_AUDIOFILE */
/* 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 program is free software; you can redistribute it and/or modify
......@@ -64,8 +64,13 @@ static MDRIVER drv_mpd = {
"MPD Output Driver v0.1",
0,
255,
"mpd",
NULL,
#if (LIBMIKMOD_VERSION > 0x030106)
"mpd", /* Alias */
#if (LIBMIKMOD_VERSION > 0x030200)
NULL, /* CmdLineHelp */
#endif
NULL, /* CommandLine */
#endif
mod_mpd_IsThere,
VC_SampleLoad,
VC_SampleUnload,
......@@ -92,8 +97,8 @@ static MDRIVER drv_mpd = {
VC_VoiceRealVolume
};
static int mod_mikModInitiated = 0;
static int mod_mikModInitError = 0;
static int mod_mikModInitiated;
static int mod_mikModInitError;
static int mod_initMikMod(void)
{
......@@ -143,6 +148,9 @@ static mod_Data *mod_open(char *path)
if (!(moduleHandle = Player_Load(path, 128, 0)))
return NULL;
/* Prevent module from looping forever */
moduleHandle->loop = 0;
data = xmalloc(sizeof(mod_Data));
data->audio_buffer = xmalloc(MIKMOD_FRAME_SIZE);
......@@ -177,6 +185,7 @@ static int mod_decode(OutputBuffer * cb, DecoderControl * dc, char *path)
return -1;
}
dc->totalTime = 0;
dc->audioFormat.bits = 16;
dc->audioFormat.sampleRate = 44100;
dc->audioFormat.channels = 2;
......@@ -285,17 +294,6 @@ InputPlugin modPlugin = {
#else
InputPlugin modPlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
InputPlugin modPlugin;
#endif /* HAVE_AUDIOFILE */
#endif /* HAVE_MIKMOD */
/* 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 program is free software; you can redistribute it and/or modify
......@@ -31,6 +31,7 @@
#include "../utils.h"
#include "../replayGain.h"
#include "../tag.h"
#include "../conf.h"
#include <stdio.h>
#include <stdlib.h>
......@@ -55,6 +56,10 @@
/* the number of samples of silence the decoder inserts at start */
#define DECODERDELAY 529
#define DEFAULT_GAPLESS_MP3_PLAYBACK 1
static int gaplessPlayback;
/* this is stolen from mpg321! */
struct audio_dither {
mad_fixed_t error[3];
......@@ -113,6 +118,14 @@ static signed long audio_linear_dither(unsigned int bits, mad_fixed_t sample,
/* 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 */
#define MP3_DATA_OUTPUT_BUFFER_SIZE 4096
......@@ -679,7 +692,8 @@ static int decodeFirstFrame(mp3DecodeData * data, DecoderControl * dc,
data->foundXing = 1;
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->dropSamplesAtEnd = lame.encoderPadding;
}
......@@ -759,8 +773,6 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
mad_timer_add(&data->timer, (data->frame).header.duration);
data->bitRate = (data->frame).header.bitrate;
if (data->currentFrame >= data->maxFrames) {
/* stop decoding, since Xing maxFrames is accurate */
if (data->foundXing) return DECODE_BREAK;
data->currentFrame = data->maxFrames - 1;
} else {
data->highestFrame++;
......@@ -811,8 +823,9 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
break;
} else if ((data->dropFramesAtEnd > 0) &&
(data->currentFrame == (data->maxFrames + 1 - data->dropFramesAtEnd))) {
data->dropFramesAtEnd--;
break;
/* stop decoding, effectively dropping all remaining
* frames */
return DECODE_BREAK;
}
if (data->inStream->metaTitle) {
......@@ -835,59 +848,43 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
for (i = 0; i < (data->synth).pcm.length; i++) {
mpd_sint16 *sample;
samplesLeft--;
if (!data->decodedFirstFrame &&
(i < data->dropSamplesAtStart)) {
continue;
} else if (data->dropSamplesAtEnd &&
(data->currentFrame == (data->maxFrames - data->dropFramesAtEnd))) {
samplesLeft--;
/* stop decoding, since samples were dropped */
if (samplesLeft < data->dropSamplesAtEnd)
return DECODE_BREAK;
(data->currentFrame == (data->maxFrames - data->dropFramesAtEnd)) &&
(samplesLeft < data->dropSamplesAtEnd)) {
/* stop decoding, effectively dropping
* all remaining samples */
return DECODE_BREAK;
}
sample = (mpd_sint16 *) data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->
synth).pcm.
samples[0]
[i],
&(data->
dither));
(data->synth).pcm.samples[0][i],
&(data->dither));
data->outputPtr += 2;
if (MAD_NCHANNELS(&(data->frame).header) == 2) {
sample = (mpd_sint16 *) data->outputPtr;
*sample = (mpd_sint16) audio_linear_dither(16,
(data->
synth).
pcm.
samples
[1]
[i],
&
(data->
dither));
(data->synth).pcm.samples[1][i],
&(data->dither));
data->outputPtr += 2;
}
if (data->outputPtr >= data->outputBufferEnd) {
long ret;
ret = sendDataToOutputBuffer(cb,
data->inStream,
dc,
data->inStream->
seekable,
data->outputBuffer,
data->outputPtr -
data->inStream->seekable,
data->outputBuffer,
data->outputPtr - data->outputBuffer,
data->elapsedTime,
data->bitRate /
1000,
(replayGainInfo !=
NULL) ?
*replayGainInfo :
NULL);
data->bitRate / 1000,
(replayGainInfo != NULL) ? *replayGainInfo : NULL);
if (ret == OUTPUT_BUFFER_DC_STOP) {
data->flush = 0;
return DECODE_BREAK;
......@@ -903,21 +900,21 @@ static int mp3Read(mp3DecodeData * data, OutputBuffer * cb, DecoderControl * dc,
data->decodedFirstFrame = 1;
if (dc->seek && data->inStream->seekable) {
long i = 0;
long j = 0;
data->muteFrame = MUTEFRAME_SEEK;
while (i < data->highestFrame && dc->seekWhere >
((float)mad_timer_count(data->times[i],
while (j < data->highestFrame && dc->seekWhere >
((float)mad_timer_count(data->times[j],
MAD_UNITS_MILLISECONDS))
/ 1000) {
i++;
j++;
}
if (i < data->highestFrame) {
if (j < data->highestFrame) {
if (seekMp3InputBuffer(data,
data->frameOffset[i]) ==
data->frameOffset[j]) ==
0) {
data->outputPtr = data->outputBuffer;
clearOutputBuffer(cb);
data->currentFrame = i;
data->currentFrame = j;
} else
dc->seekError = 1;
data->muteFrame = 0;
......@@ -1078,7 +1075,7 @@ static char *mp3_mimeTypes[] = { "audio/mpeg", NULL };
InputPlugin mp3Plugin = {
"mp3",
NULL,
mp3_plugin_init,
NULL,
NULL,
mp3_decode,
......@@ -1090,17 +1087,6 @@ InputPlugin mp3Plugin = {
};
#else
InputPlugin mp3Plugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
InputPlugin mp3Plugin;
#endif
#endif /* HAVE_MAD */
/* 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 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)
faacDecConfigurationPtr config;
unsigned char *mp4Buffer;
unsigned int mp4BufferSize;
uint32_t sampleRate;
unsigned long sampleRate;
unsigned char channels;
long sampleId;
long numSamples;
......@@ -450,17 +450,6 @@ InputPlugin mp4Plugin = {
#else
InputPlugin mp4Plugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
InputPlugin mp4Plugin;
#endif /* HAVE_FAAD */
/* 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 program is free software; you can redistribute it and/or modify
......@@ -338,7 +338,6 @@ static MpdTag *mpcTagDup(char *file)
}
static char *mpcSuffixes[] = { "mpc", NULL };
static char *mpcMimeTypes[] = { NULL };
InputPlugin mpcPlugin = {
"mpc",
......@@ -350,22 +349,11 @@ InputPlugin mpcPlugin = {
mpcTagDup,
INPUT_PLUGIN_STREAM_URL | INPUT_PLUGIN_STREAM_FILE,
mpcSuffixes,
mpcMimeTypes
NULL
};
#else
InputPlugin mpcPlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL
};
InputPlugin mpcPlugin;
#endif
#endif /* HAVE_MPCDEC */
/* 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
*
* OggFLAC support (half-stolen from flac_plugin.c :))
......@@ -19,11 +19,10 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
#include "../inputPlugin.h"
#include "_flac_common.h"
#ifdef HAVE_OGGFLAC
#include "_flac_common.h"
#include "_ogg_common.h"
#include "../utils.h"
......@@ -37,8 +36,6 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <OggFLAC/seekable_stream_decoder.h>
#include <FLAC/metadata.h>
static void oggflac_cleanup(InputStream * inStream,
FlacData * data,
......@@ -401,7 +398,10 @@ fail:
}
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 = {
"oggflac",
......@@ -418,17 +418,6 @@ InputPlugin oggflacPlugin = {
#else /* !HAVE_FLAC */
InputPlugin oggflacPlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
InputPlugin oggflacPlugin;
#endif /* HAVE_OGGFLAC */
/* 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 program is free software; you can redistribute it and/or modify
......@@ -409,7 +409,10 @@ static unsigned int oggvorbis_try_decode(InputStream * inStream)
}
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 = {
"oggvorbis",
......@@ -426,17 +429,6 @@ InputPlugin oggvorbisPlugin = {
#else /* !HAVE_OGGVORBIS */
InputPlugin oggvorbisPlugin = {
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0,
NULL,
NULL,
};
InputPlugin oggvorbisPlugin;
#endif /* HAVE_OGGVORBIS */
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -25,6 +25,8 @@
#include <sys/types.h>
#include <unistd.h>
#include <errno.h>
#define _XOPEN_SOURCE 600
#include <fcntl.h>
void inputStream_initFile(void)
{
......@@ -46,6 +48,10 @@ int inputStream_fileOpen(InputStream * inStream, char *filename)
inStream->size = ftell(fp);
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->seekFunc = inputStream_fileSeek;
inStream->closeFunc = inputStream_fileClose;
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -47,10 +47,10 @@
#define HTTP_REDIRECT_MAX 10
static char *proxyHost = NULL;
static char *proxyPort = NULL;
static char *proxyUser = NULL;
static char *proxyPassword = NULL;
static char *proxyHost;
static char *proxyPort;
static char *proxyUser;
static char *proxyPassword;
static int bufferSize = HTTP_BUFFER_SIZE_DEFAULT;
static int prebufferSize = HTTP_PREBUFFER_SIZE_DEFAULT;
......@@ -81,9 +81,8 @@ void inputStream_initHttp(void)
param = getConfigParam(CONF_HTTP_PROXY_PORT);
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);
exit(EXIT_FAILURE);
}
proxyPort = param->value;
......@@ -95,35 +94,30 @@ void inputStream_initHttp(void)
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
if (!param) {
ERROR("%s specified but not %s\n",
FATAL("%s specified but not %s\n",
CONF_HTTP_PROXY_USER,
CONF_HTTP_PROXY_PASSWORD);
exit(EXIT_FAILURE);
}
proxyPassword = param->value;
}
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
} else {
param = getConfigParam(CONF_HTTP_PROXY_PASSWORD);
if (param) {
ERROR("%s specified but not %s\n",
CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
exit(EXIT_FAILURE);
if (param) {
FATAL("%s specified but not %s\n",
CONF_HTTP_PROXY_PASSWORD, CONF_HTTP_PROXY_USER);
}
}
} 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);
exit(EXIT_FAILURE);
} 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);
exit(EXIT_FAILURE);
} 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,
param->line);
exit(EXIT_FAILURE);
}
param = getConfigParam(CONF_HTTP_BUFFER_SIZE);
......@@ -132,10 +126,9 @@ void inputStream_initHttp(void)
bufferSize = strtol(param->value, &test, 10);
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",
param->value, CONF_HTTP_BUFFER_SIZE, param->line);
exit(EXIT_FAILURE);
}
bufferSize *= 1024;
......@@ -150,11 +143,10 @@ void inputStream_initHttp(void)
prebufferSize = strtol(param->value, &test, 10);
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",
param->value, CONF_HTTP_PREBUFFER_SIZE,
param->line);
exit(EXIT_FAILURE);
}
prebufferSize *= 1024;
......@@ -446,7 +438,8 @@ static int finishHTTPInit(InputStream * inStream)
int error;
socklen_t error_len = sizeof(int);
int ret;
char request[2049];
int length;
char request[2048];
tv.tv_sec = 0;
tv.tv_usec = 0;
......@@ -463,42 +456,41 @@ static int finishHTTPInit(InputStream * inStream)
if (ret < 0) {
DEBUG(__FILE__ ": problem select'ing: %s\n", strerror(errno));
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
goto close_err;
}
getsockopt(data->sock, SOL_SOCKET, SO_ERROR, &error, &error_len);
if (error) {
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
}
if (error)
goto close_err;
memset(request, 0, 2049);
/* 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"
/*"Connection: close\r\n" */
"User-Agent: %s/%s\r\n"
/*"Range: bytes=%ld-\r\n" */
"%s" /* authorization */
"Icy-Metadata:1\r\n"
"\r\n", data->path, data->host, PACKAGE_NAME, PACKAGE_VERSION,
/*inStream->offset, */
data->proxyAuth ? data->proxyAuth :
(data->httpAuth ? data->httpAuth : "")
);
ret = write(data->sock, request, strlen(request));
if (ret != strlen(request)) {
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
}
length = snprintf(request, sizeof(request),
"GET %s HTTP/1.1\r\n" "Host: %s\r\n"
/*"Connection: close\r\n" */
"User-Agent: %s/%s\r\n"
"Range: bytes=%ld-\r\n"
"%s" /* authorization */
"Icy-Metadata:1\r\n"
"\r\n",
data->path, data->host,
PACKAGE_NAME, PACKAGE_VERSION,
inStream->offset,
data->proxyAuth ? data->proxyAuth :
(data->httpAuth ? data->httpAuth : ""));
if (length >= sizeof(request))
goto close_err;
ret = write(data->sock, request, length);
if (ret != length)
goto close_err;
data->connState = HTTP_CONN_STATE_HELLO;
return 0;
close_err:
close(data->sock);
data->connState = HTTP_CONN_STATE_CLOSED;
return -1;
}
static int getHTTPHello(InputStream * inStream)
......@@ -681,9 +673,6 @@ static int getHTTPHello(InputStream * inStream)
data->prebuffer = 1;
/*mark as unseekable till we actually implement seeking */
inStream->seekable = 0;
return 0;
}
......@@ -714,21 +703,33 @@ int inputStream_httpOpen(InputStream * inStream, char *url)
int inputStream_httpSeek(InputStream * inStream, long offset, int whence)
{
/* hack to reopen an HTTP stream if we're trying to seek to
* the beginning */
if ((whence == SEEK_SET) && (offset == 0)) {
InputStreamHTTPData *data;
InputStreamHTTPData *data;
data = (InputStreamHTTPData *) inStream->data;
close(data->sock);
data->connState = HTTP_CONN_STATE_REOPEN;
data->buflen = 0;
inStream->offset = 0;
return 0;
if (!inStream->seekable)
return -1;
switch (whence) {
case SEEK_SET:
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 */
return -1;
data = (InputStreamHTTPData *)inStream->data;
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)
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -26,6 +26,7 @@
#include "permission.h"
#include "sllist.h"
#include "utils.h"
#include "ioops.h"
#include <stdio.h>
#include <stdlib.h>
......@@ -55,20 +56,23 @@
#define INTERFACE_MAX_OUTPUT_BUFFER_SIZE_DEFAULT (8192*1024)
/* 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 size_t interface_max_command_list_size =
INTERFACE_MAX_COMMAND_LIST_DEFAULT;
static size_t interface_max_output_buffer_size =
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 */
static long int interface_list_cache_size = 32;
/* shared globally between all interfaces: */
static struct strnode *list_cache = NULL;
static struct strnode *list_cache_head = NULL;
static struct strnode *list_cache_tail = NULL;
static struct strnode *list_cache;
static struct strnode *list_cache_head;
static struct strnode *list_cache_tail;
typedef struct _Interface {
char buffer[INTERFACE_MAX_BUFFER_LENGTH];
......@@ -94,7 +98,7 @@ typedef struct _Interface {
int send_buf_alloc; /* bytes actually allocated */
} Interface;
static Interface *interfaces = NULL;
static Interface *interfaces;
static void flushInterfaceBuffer(Interface * interface);
......@@ -489,6 +493,7 @@ int doIOForInterfaces(void)
{
fd_set rfds;
fd_set wfds;
fd_set efds;
struct timeval tv;
int i;
int selret;
......@@ -500,12 +505,43 @@ int doIOForInterfaces(void)
while (1) {
fdmax = 0;
FD_ZERO( &rfds );
FD_ZERO( &wfds );
FD_ZERO( &efds );
addInterfacesReadyToReadAndListenSocketToFdSet(&rfds, &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;
if (selret < 0) {
......@@ -549,10 +585,9 @@ void initInterfaces(void)
if (param) {
interface_timeout = strtol(param->value, &test, 10);
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,
param->line);
exit(EXIT_FAILURE);
}
}
......@@ -561,9 +596,8 @@ void initInterfaces(void)
if (param) {
interface_max_connections = strtol(param->value, &test, 10);
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);
exit(EXIT_FAILURE);
}
} else
interface_max_connections = INTERFACE_MAX_CONNECTIONS_DEFAULT;
......@@ -574,9 +608,8 @@ void initInterfaces(void)
interface_max_command_list_size = strtol(param->value,
&test, 10);
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);
exit(EXIT_FAILURE);
}
interface_max_command_list_size *= 1024;
}
......@@ -587,9 +620,8 @@ void initInterfaces(void)
interface_max_output_buffer_size = strtol(param->value,
&test, 10);
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);
exit(EXIT_FAILURE);
}
interface_max_output_buffer_size *= 1024;
}
......@@ -696,7 +728,7 @@ static void flushInterfaceBuffer(Interface * interface)
int interfacePrintWithFD(int fd, char *buffer, int buflen)
{
static int i = 0;
static int i;
int copylen;
Interface *interface;
......@@ -795,3 +827,25 @@ static void printInterfaceOutBuffer(Interface * interface)
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)
* (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 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)
* (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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -53,7 +53,7 @@ typedef struct _List {
ListNode **nodesArray;
/* sorted */
int sorted;
/* weather to strdup() key's on insertion */
/* whether to strdup() key's on insertion */
int strdupKeys;
} List;
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -41,17 +41,19 @@
#define DEFAULT_PORT 6600
#define BINDERROR() do { \
ERROR("unable to bind port %u: %s\n", port, strerror(errno)); \
ERROR("maybe MPD is still running?\n"); \
FATAL("unable to bind port %u: %s\n" \
"maybe MPD is still running?\n", \
port, strerror(errno)); \
} while (0);
int *listenSockets = NULL;
int numberOfListenSockets = 0;
static int *listenSockets;
static int numberOfListenSockets;
static int boundPort;
static int establishListen(unsigned int port,
struct sockaddr *addrp, socklen_t addrlen)
{
int pf;
int pf = 0;
int sock;
int allowReuse = ALLOW_REUSE;
......@@ -68,25 +70,20 @@ static int establishListen(unsigned int port,
pf = PF_UNIX;
break;
default:
ERROR("unknown address family: %i\n", addrp->sa_family);
exit(EXIT_FAILURE);
FATAL("unknown address family: %i\n", addrp->sa_family);
}
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0) {
ERROR("socket < 0\n");
exit(EXIT_FAILURE);
}
if ((sock = socket(pf, SOCK_STREAM, 0)) < 0)
FATAL("socket < 0\n");
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));
exit(EXIT_FAILURE);
}
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&allowReuse,
sizeof(allowReuse)) < 0) {
ERROR("problems setsockopt'ing: %s\n", strerror(errno));
exit(EXIT_FAILURE);
FATAL("problems setsockopt'ing: %s\n", strerror(errno));
}
if (bind(sock, addrp, addrlen) < 0) {
......@@ -94,10 +91,8 @@ static int establishListen(unsigned int port,
return -1;
}
if (listen(sock, 5) < 0) {
ERROR("problems listen'ing: %s\n", strerror(errno));
exit(EXIT_FAILURE);
}
if (listen(sock, 5) < 0)
FATAL("problems listen'ing: %s\n", strerror(errno));
numberOfListenSockets++;
listenSockets =
......@@ -110,8 +105,8 @@ static int establishListen(unsigned int port,
static void parseListenConfigParam(unsigned int port, ConfigParam * param)
{
struct sockaddr *addrp;
socklen_t addrlen;
struct sockaddr *addrp = NULL;
socklen_t addrlen = 0;
struct sockaddr_in sin;
#ifdef HAVE_IPV6
struct sockaddr_in6 sin6;
......@@ -132,10 +127,8 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
sin6.sin6_addr = in6addr_any;
addrp = (struct sockaddr *)&sin6;
addrlen = sizeof(struct sockaddr_in6);
if (establishListen(port, addrp, addrlen) < 0) {
if (establishListen(port, addrp, addrlen) < 0)
BINDERROR();
exit(EXIT_FAILURE);
}
}
#endif
sin.sin_addr.s_addr = INADDR_ANY;
......@@ -147,24 +140,21 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
if (establishListen(port, addrp, addrlen) < 0) {
#endif
BINDERROR();
exit(EXIT_FAILURE);
}
} else {
struct hostent *he;
DEBUG("binding to address for %s\n", 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);
exit(EXIT_FAILURE);
}
switch (he->h_addrtype) {
#ifdef HAVE_IPV6
case AF_INET6:
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",
param->value, param->line);
exit(EXIT_FAILURE);
}
memcpy((char *)&sin6.sin6_addr.s6_addr,
(char *)he->h_addr, he->h_length);
......@@ -179,15 +169,12 @@ static void parseListenConfigParam(unsigned int port, ConfigParam * param)
addrlen = sizeof(struct sockaddr_in);
break;
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);
exit(EXIT_FAILURE);
}
if (establishListen(port, addrp, addrlen) < 0) {
if (establishListen(port, addrp, addrlen) < 0)
BINDERROR();
exit(EXIT_FAILURE);
}
}
}
......@@ -195,22 +182,20 @@ void listenOnPort(void)
{
int port = DEFAULT_PORT;
ConfigParam *param = getNextConfigParam(CONF_BIND_TO_ADDRESS, NULL);
{
ConfigParam *portParam = getConfigParam(CONF_PORT);
if (portParam) {
char *test;
port = strtol(portParam->value, &test, 10);
if (port <= 0 || *test != '\0') {
ERROR("%s \"%s\" specified at line %i is not a "
"positive integer", CONF_PORT,
portParam->value, portParam->line);
exit(EXIT_FAILURE);
}
ConfigParam *portParam = getConfigParam(CONF_PORT);
if (portParam) {
char *test;
port = strtol(portParam->value, &test, 10);
if (port <= 0 || *test != '\0') {
FATAL("%s \"%s\" specified at line %i is not a "
"positive integer", CONF_PORT,
portParam->value, portParam->line);
}
}
boundPort = port;
do {
parseListenConfigParam(port, param);
} while ((param = getNextConfigParam(CONF_BIND_TO_ADDRESS, param)));
......@@ -266,3 +251,8 @@ void getConnections(fd_set * fds)
}
}
}
int getBoundPort(void)
{
return boundPort;
}
/* 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 program is free software; you can redistribute it and/or modify
......@@ -36,4 +36,6 @@ void freeAllListenSockets(void);
/* fdmax should be initialized to something */
void addListenSocketsToFdSet(fd_set * fds, int *fdmax);
int getBoundPort(void);
#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)
* (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 program is free software; you can redistribute it and/or modify
......@@ -29,13 +29,13 @@
#include <time.h>
static unsigned int logLevel = LOG_LEVEL_LOW;
static int warningFlushed = 0;
static int warningFlushed;
static int stdout_mode = 1;
static char *warningBuffer = NULL;
static char *warningBuffer;
static int out_fd = -1;
static int err_fd = -1;
static const char *out_filename = NULL;
static const char *err_filename = NULL;
static const char *out_filename;
static const char *err_filename;
/* redirect stdin to /dev/null to work around a libao bug */
static void redirect_stdin(void)
......@@ -59,7 +59,7 @@ static void redirect_logs(void)
static const char *log_date(void)
{
static char buf[16] = { '\0' };
static char buf[16];
time_t t = time(NULL);
strftime(buf, 16, "%b %d %H:%M : ", localtime(&t));
return buf;
......@@ -68,7 +68,7 @@ static const char *log_date(void)
#define BUFFER_LENGTH 4096
static void buffer_warning(const char *fmt, va_list args)
{
char buffer[BUFFER_LENGTH + 1];
char buffer[BUFFER_LENGTH];
char *tmp = buffer;
size_t len = BUFFER_LENGTH;
......@@ -100,11 +100,10 @@ void flushWarningLog(void)
if (warningBuffer != NULL)
{
while (s != NULL) {
char * next = strchr(s, '\n');
if (next != NULL) {
*next = '\0';
next++;
}
char *next = strchr(s, '\n');
if (next == NULL) break;
*next = '\0';
next++;
fprintf(stderr, "%s\n", s);
s = next;
}
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -42,6 +42,7 @@
#include "../config.h"
#include "utils.h"
#include "normalize.h"
#include "zeroconf.h"
#include <stdio.h>
#include <sys/select.h>
......@@ -65,7 +66,6 @@ typedef struct _Options {
int daemon;
int stdOutput;
int createDB;
int updateDB;
int verbose;
} Options;
......@@ -126,7 +126,6 @@ static void usage(char *argv[])
(" --no-create-db don't create database, even if it doesn't exist\n");
ERROR(" --no-daemon don't detach from console\n");
ERROR(" --stdout print messages to stdout and stderr\n");
/*ERROR(" --update-db create database and exit\n"); */
ERROR(" --verbose verbose logging\n");
ERROR(" --version prints version information\n");
}
......@@ -135,7 +134,7 @@ static void version(void)
{
LOG("mpd (MPD: Music Player Daemon) %s\n", VERSION);
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("warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n");
LOG("\n");
......@@ -158,7 +157,6 @@ static void parseOptions(int argc, char **argv, Options * options)
options->daemon = 1;
options->stdOutput = 0;
options->createDB = 0;
options->updateDB = 0;
options->kill = 0;
if (argc > 1) {
......@@ -248,15 +246,13 @@ static void changeToUser(void)
/* get uid */
struct passwd *userpwd;
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);
exit(EXIT_FAILURE);
}
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));
exit(EXIT_FAILURE);
}
#ifdef _BSD_SOURCE
/* init suplementary groups
......@@ -271,10 +267,9 @@ static void changeToUser(void)
/* set uid */
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",
param->value, param->line, strerror(errno));
exit(EXIT_FAILURE);
}
/* this is needed by libs such as arts */
......@@ -288,10 +283,9 @@ static void openDB(Options * options, char *argv0)
{
if (options->createDB > 0 || readDirectoryDB() < 0) {
if (options->createDB < 0) {
ERROR("can't open db file and using \"--no-create-db\""
" command line option\n");
ERROR("try running \"%s --create-db\"\n", argv0);
exit(EXIT_FAILURE);
FATAL("can't open db file and using "
"\"--no-create-db\" command line option\n"
"try running \"%s --create-db\"\n", argv0);
}
flushWarningLog();
if (checkDirectoryDB() < 0)
......@@ -302,11 +296,6 @@ static void openDB(Options * options, char *argv0)
if (options->createDB)
exit(EXIT_SUCCESS);
}
if (options->updateDB) {
flushWarningLog();
updateMp3Directory();
exit(EXIT_SUCCESS);
}
}
static void daemonize(Options * options)
......@@ -320,11 +309,9 @@ static void daemonize(Options * options)
DEBUG("opening pid file\n");
fp = fopen(pidFileParam->value, "w+");
if (!fp) {
ERROR
("could not open %s \"%s\" (at line %i) for writing: %s\n",
FATAL("could not open %s \"%s\" (at line %i) for writing: %s\n",
CONF_PID_FILE, pidFileParam->value,
pidFileParam->line, strerror(errno));
exit(EXIT_FAILURE);
}
}
......@@ -336,18 +323,15 @@ static void daemonize(Options * options)
if (pid > 0)
_exit(EXIT_SUCCESS);
else if (pid < 0) {
ERROR("problems fork'ing for daemon!\n");
exit(EXIT_FAILURE);
FATAL("problems fork'ing for daemon!\n");
}
if (chdir("/") < 0) {
ERROR("problems changing to root directory\n");
exit(EXIT_FAILURE);
FATAL("problems changing to root directory\n");
}
if (setsid() < 0) {
ERROR("problems setsid'ing\n");
exit(EXIT_FAILURE);
FATAL("problems setsid'ing\n");
}
fflush(NULL);
......@@ -355,8 +339,7 @@ static void daemonize(Options * options)
if (pid > 0)
_exit(EXIT_SUCCESS);
else if (pid < 0) {
ERROR("problems fork'ing for daemon!\n");
exit(EXIT_FAILURE);
FATAL("problems fork'ing for daemon!\n");
}
DEBUG("daemonized!\n");
......@@ -388,26 +371,22 @@ static void killFromPidFile(char *cmd, int killOption)
int pid;
if (!pidFileParam) {
ERROR("no pid_file specified in the config file\n");
exit(EXIT_FAILURE);
FATAL("no pid_file specified in the config file\n");
}
fp = fopen(pidFileParam->value, "r");
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));
exit(EXIT_FAILURE);
}
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);
exit(EXIT_FAILURE);
}
fclose(fp);
if (kill(pid, SIGTERM)) {
ERROR("unable to kill proccess %i: %s\n", pid, strerror(errno));
exit(EXIT_FAILURE);
FATAL("unable to kill proccess %i: %s\n", pid, strerror(errno));
}
exit(EXIT_SUCCESS);
}
......@@ -430,7 +409,7 @@ int main(int argc, char *argv[])
initTagConfig();
initLog(options.verbose);
if (options.createDB <= 0 && !options.updateDB)
if (options.createDB <= 0)
listenOnPort();
changeToUser();
......@@ -450,6 +429,7 @@ int main(int argc, char *argv[])
initAudioDriver();
initVolume();
initInterfaces();
initZeroconf();
initReplayGainState();
initNormalization();
initInputStream();
......@@ -475,6 +455,7 @@ int main(int argc, char *argv[])
write_state_file();
playerKill();
finishZeroconf();
freeAllInterfaces();
closeAllListenSockets();
finishPlaylist();
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 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)
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;
size_t len;
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......
/* 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 program is free software; you can redistribute it and/or modify
......@@ -30,7 +30,7 @@
static mpd_sint16 currentChunk = -1;
static mpd_sint8 currentMetaChunk = -1;
static mpd_sint8 sendMetaChunk = 0;
static mpd_sint8 sendMetaChunk;
void clearAllMetaChunkSets(OutputBuffer * cb)
{
......@@ -58,11 +58,10 @@ void clearOutputBuffer(OutputBuffer * cb)
void flushOutputBuffer(OutputBuffer * cb)
{
if (currentChunk == cb->end) {
int next = cb->end + 1;
if (next >= buffered_chunks) {
next = 0;
if ((cb->end + 1) >= buffered_chunks) {
cb->end = 0;
}
cb->end = next;
else cb->end++;
currentChunk = -1;
}
}
......@@ -76,27 +75,23 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
mpd_uint16 chunkLeft;
char *data;
size_t datalen;
static char *convBuffer = NULL;
static long convBufferLen = 0;
static char *convBuffer;
static long convBufferLen;
if (cmpAudioFormat(&(cb->audioFormat), &(dc->audioFormat)) == 0) {
data = dataIn;
datalen = dataInLen;
} else {
datalen =
pcm_sizeOfOutputBufferForAudioFormatConversion(&
(dc->
audioFormat),
dataInLen,
&(cb->
audioFormat));
datalen = pcm_sizeOfConvBuffer(&(dc->audioFormat), dataInLen,
&(cb->audioFormat));
if (datalen > convBufferLen) {
convBuffer = xrealloc(convBuffer, datalen);
convBufferLen = datalen;
}
data = convBuffer;
pcm_convertAudioFormat(&(dc->audioFormat), dataIn, dataInLen,
&(cb->audioFormat), data);
datalen = pcm_convertAudioFormat(&(dc->audioFormat), dataIn,
dataInLen, &(cb->audioFormat),
data, &(cb->convState));
}
if (replayGainInfo && (replayGainState != REPLAYGAIN_OFF))
......@@ -158,7 +153,7 @@ int sendDataToOutputBuffer(OutputBuffer * cb, InputStream * inStream,
int copyMpdTagToOutputBuffer(OutputBuffer * cb, MpdTag * tag)
{
int nextChunk;
static MpdTag *last = NULL;
static MpdTag *last;
if (!cb->acceptMetadata || !tag) {
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