Compare commits

...

84 Commits

Author SHA1 Message Date
Avuton Olrich
e2950a7e4d mpd version 0.16.3 2011-06-04 07:37:33 -07:00
Max Kellermann
4b4aa64261 directory: allow directories with just playlists
Keep those when scanning for empty directories.  The check in
playlist_vector_is_empty() was missing.
2011-05-09 21:37:43 +02:00
Max Kellermann
26735390ff playlist_song: fix playlist files in base music directory
g_path_get_dirname() returns "." when there is no directory name in
the given path.  This patch adds a workaround for that.
2011-05-09 18:05:11 +02:00
Max Kellermann
9402b23dd5 playlist_song: fix NULL pointer dereference 2011-05-09 18:03:54 +02:00
Max Kellermann
246db3d565 decoder/ffmpeg: use avcodec_decode_audio3() if available
avcodec_decode_audio3() has been added in libavformat 52.25.0, and the
predecessor avcodec_decode_audio2() has been deprecated.
2011-05-09 09:24:17 +02:00
Max Kellermann
eaf414cbc8 decoder/ffmpeg: make variables more local 2011-05-09 09:24:15 +02:00
Anton Khirnov
327d41c00f decoder/ffmpeg: don't use deprecated CODEC_TYPE_AUDIO with new lavc
fixes build with lavc 53.
2011-05-09 08:00:45 +02:00
Max Kellermann
05d8ce3bcd decoder/ffmpeg: define fallback macro AV_VERSION_INT()
For ffmpeg < 0.5.  Copied from libavutil 0.5.
2011-05-09 08:00:45 +02:00
Max Kellermann
def2fe8805 Merge branch 'v0.15.x' into v0.16.x
Conflicts:
	NEWS
	configure.ac
	src/listen.c
2011-04-12 07:39:01 +02:00
Max Kellermann
f680b0a431 decoder/flac: fix enum mismatch in flac_tell_cb()
Fix clang warning.
2011-03-23 22:31:40 +01:00
Max Kellermann
d4b00ff11c listen: suppress "unused variable" warning 2011-03-23 22:27:31 +01:00
Max Kellermann
532f94a187 audio_parser: fix assertion failure in audio format mask parser
Use audio_format_mask_valid() to verify a mask.
2011-03-23 22:22:51 +01:00
Max Kellermann
87ad2f8542 command: fix return value of handle_currentsong()
Thanks to clang for complaining.
2011-03-23 22:16:46 +01:00
Simon Kagstrom
a8f891efcd configure.ac: Enable HAVE_OGG_COMMON when using libtremor
Otherwise OGGs can't be played.
2011-03-23 22:09:58 +01:00
Avuton Olrich
b5fc2419e8 Modify version string to post-release version 0.16.3~git 2011-03-18 17:43:11 -07:00
Avuton Olrich
fe588a255b mpd version 0.16.2 2011-03-18 17:43:11 -07:00
Max Kellermann
1fc571088b command: print playlist load error
Call print_playlist_result() instead of casting the enum implicitly.
2011-03-18 19:45:59 +01:00
Max Kellermann
8d83914f05 output/httpd: include sys/socket.h only when building with libwrap
Fixes build failure on WIN32.
2011-03-18 19:44:12 +01:00
Max Kellermann
0fdcd381bc update_walk: ignore parameter "mode" on WIN32
Fix compiler warning.
2011-03-18 19:43:26 +01:00
Max Kellermann
4f293ecd6f audio_format, output_thread: add more audio_format_valid() assertions 2011-03-16 23:37:41 +01:00
Max Kellermann
b6303313f0 encoder/vorbis: reset the Ogg stream after flush
Without the ogg_stream_reset() call, the "e_o_s" flag never gets
reset, and libogg writes EOS packets over and over.
2011-03-16 19:16:06 +01:00
Max Kellermann
a28449a123 encoder/vorbis: reset the Ogg stream after flush
Without the ogg_stream_reset() call, the "e_o_s" flag never gets
reset, and libogg writes EOS packets over and over.
2011-03-16 19:13:46 +01:00
Max Kellermann
6dcec36621 Merge release 0.15.16 into v0.16.x
Conflicts:
	NEWS
	configure.ac
	src/output/jack_plugin.c
	src/update.c
2011-03-16 18:08:54 +01:00
Avuton Olrich
84d0fd39a3 Modify version string to post-release version 0.15.17~git 2011-03-13 20:27:33 -07:00
Avuton Olrich
4d4b7e3de0 mpd version 0.15.16 2011-03-13 20:27:33 -07:00
Ulrich Spörlein
e2aea6bce5 output/httpd: include sys/socket.h for AF_UNIX 2011-03-09 19:53:48 +01:00
Ulrich Spörlein
5779146a7f configure.ac: fix bashism in tremor test
This makes FreeBSD detect libogg correctly. The '==' operator is an
undocumented GNU extension to test(1) and cannot be relied upon to
exist and do the right thing. POSIX mandates string comparisons to be
done using "test foo = bar".
2011-03-09 19:50:54 +01:00
Max Kellermann
a1d1c2beaa output/oss: disable 24 bit playback on FreeBSD
See code comment.
2011-02-28 00:09:45 +01:00
Max Kellermann
ee9c60fad4 output/oss: AFMT_S24_PACKED is little-endian
According to the Solaris dsp manpage, AFMT_S24_PACKED is
little-endian:

 http://download.oracle.com/docs/cd/E19963-01/821-1475/6nmf5baot/index.html

The Minix soundcard.h header says the same.
2011-02-28 00:00:41 +01:00
Max Kellermann
1674a4ec82 output/jack: fix crash with mono playback
With mono sound, jack_sample_size is smaller than frame_size (4 vs 2
bytes), and "space/jack_sample_size==0".  That means mpd_jack_play()
will return 0, although no error has occurred.
2011-02-27 23:26:50 +01:00
Max Kellermann
ce370bee60 output/jack: rename variable sample_size to jack_sample_size 2011-02-25 10:46:44 +01:00
Max Kellermann
e257484870 Makefile.am: distribute test/stdbin.h 2011-02-18 08:19:37 +01:00
Christopher Brannon
2a1f4539f6 Insure proper initialization of stack-allocated struct.
Version 1.0.0 of the libao library added a new field to the
ao_sample_format struct.  It is a char * named matrix.  When
an ao_sample_format is allocated on the stack, this field contains
garbage.  The proper course is to insure that is initialized to NULL.
NULL indicates that we do not want any mapping.
The struct is now initialized using a static initializer, and this
technique is compatible with all known versions of libao.
2011-02-15 12:16:25 +01:00
Max Kellermann
906efdd320 Makefile.am: compile test/run_encoder with ENCODER_CFLAGS 2011-02-13 23:22:57 +01:00
Thomas Jansen
948b8f35e6 general: whitespace cleanup
Remove trailing whitespace found by this command:
find -name '*.[ch]' | xargs grep "[[:space:]]$"
2011-02-09 22:42:31 +01:00
Thomas Jansen
e776c605ad output/httpd: initialize unflushed_input
This fixes the following valgrind warning occuring on the first call of
httpd_output_read_page:
==20124== Conditional jump or move depends on uninitialised value(s)
==20124==    at 0x425E65: httpd_output_read_page (httpd_output_plugin.c:240)
==20124==    by 0x426087: httpd_output_open (httpd_output_plugin.c:279)
==20124==    by 0x41D862: ao_open (output_plugin.h:206)
==20124==    by 0x41E133: audio_output_task (output_thread.c:590)
2011-02-09 22:41:36 +01:00
Tony Miller
8b2f4fc823 Set fadeout in gme_decoder_plugin. Due to the nature of the gme library,
this needs to be done for the end of songs to be detected.
2011-02-03 00:25:35 +01:00
Max Kellermann
03018611f8 update: log all file permission problems 2011-01-31 09:39:24 +01:00
Max Kellermann
8f99c954ad NEWS: fix 0.16.1 release year 2011-01-28 21:12:17 +01:00
Max Kellermann
5735c9efc1 configure.ac: fix tremor configure test
When the configure options were moved around for 0.16, the order was
changed, and the Tremor check broke.
2011-01-28 12:21:03 +01:00
Andreas Wiese
e6c3acaa6f Fix NDEBUG test
<stdbool.h> needs to be included unconditionally from definition of
NDEBUG, since »bool« doesn't get defined otherwise.

Signed-off-by: Andreas Wiese <aw-devel@meterriblecrew.net>
2011-01-14 16:22:25 +01:00
Avuton Olrich
44b4b50949 Modify version string to post-release version 0.16.2~git 2011-01-09 18:00:12 -08:00
Avuton Olrich
9ad862d3a6 mpd version 0.16.1 2011-01-09 18:00:12 -08:00
Yuriy Kaminskiy
77d71c4ee6 Makefile.am: resolve modplug vs. libsndfile cflags/headers conflict
A bit of automake magic (see info automake "Per-Object Flags").
Compile-tested.
2011-01-09 18:21:27 +01:00
Max Kellermann
8c0afd8557 Merge branch 'v0.15.x' into v0.16.x
Conflicts:
	NEWS
	configure.ac
	src/directory.h
2011-01-07 23:50:23 +01:00
Max Kellermann
2a56300f7b player_thread: discard empty chunks while cross-fading
When a music_chunk to be crossfaded consists only of a tag,
cross-fading is not possible, and led to an assertion failure.  This
patch just discards those, as if cross-fading was not enabled.
2011-01-07 23:45:51 +01:00
Max Kellermann
5f06999686 output_thread: fix double lock
During the whole output thread, the audio_output object is locked, and
it is only unlocked while waiting for the GCond and while running a
plugin method.  The error handler in ao_play_chunk() attempted to lock
the object again, which was code from MPD 0.15.x which should have
been removed a long time ago.
2011-01-07 23:08:18 +01:00
Max Kellermann
4c09aeb5a1 player_thread: fix assertion failure due to early seek
Until the decoder plugin has called decoder_initialized(), the player
may not submit seek commands.  This however could occur with a slow
decoder and a CUE file with a virtual song offset.  This patch adds
another check.
2011-01-07 22:52:50 +01:00
Max Kellermann
af892e7e80 player_thread: make variables more local 2011-01-07 22:33:10 +01:00
Max Kellermann
0022fb100b encoder/lame: explicitly configure the output sample rate
When you don't explicitly set an output sample rate, liblame tries to
guess an output sample rate from the input sample rate.  You would
think that this "guessing" consists of just setting both equal, but
that is not the case.  For 44.1kHz at 96kbit/s, liblame chooses
32kHz.  This patch explicitly configures the output sample rate, to
stop the bad guessing.
2011-01-07 19:37:39 +01:00
Max Kellermann
4f2d67dfb0 output/httpd: define G_LOG_DOMAIN in httpd_client.c 2011-01-07 18:00:12 +01:00
Max Kellermann
b5645ab29f output/osx: fix up audio format first, then apply it to device
This is a MPD 0.16 regression: when playing a 24 bit file, the switch
to 16 bit was made only partially, after mBytesPerPacket and
mBytesPerFrame had already been applied.

That means mBytesPerFrame referred to 24 bit, and mBitsPerChannel
referred to 16 bits.  Of course, that cannot work.
2011-01-07 17:31:36 +01:00
Max Kellermann
3149d1abf9 configure.ac: eliminate bashism "echo -n"
Use "printf" instead.
2011-01-07 17:31:30 +01:00
Max Kellermann
59a417fc84 configure.ac: avoid GNU extension in "expr match" call 2011-01-07 17:29:19 +01:00
Max Kellermann
b75d53413d configure.ac: use AC_LANG_SOURCE
Fixes autotools warnings.
2011-01-07 17:25:52 +01:00
Max Kellermann
c44a744c0b fix version number in NEWS 2011-01-07 17:25:25 +01:00
Max Kellermann
76cddfab90 configure.ac: disable the FFADO plugin by default
It is known to crash instantly.
2010-12-22 07:31:17 +01:00
Max Kellermann
60b4f6b3eb directory: fix warning "comparison between signed and unsigned"
Cast the constant to dev_t, not to unsigned.
2010-12-21 20:21:22 +01:00
Max Kellermann
546232b1c0 zeroconf-bonjour: use g_htons() instead of htons()
Fixes the gcc warning "implicit declaration of function 'htons'".
2010-12-21 20:21:20 +01:00
Max Kellermann
42c5788de3 Modify version string to post-release version 0.15.16~git 2010-12-21 20:19:49 +01:00
Max Kellermann
fb00e7fddc add void casts to suppress "result unused" warnings (clang) 2010-12-21 08:06:02 +01:00
Alex Viskovatoff
41fdcf328c decoder/mad: work around build failure on Solaris
Rename the "version" struct, because it seems to be a reserved name on
Solaris:

 "src/decoder/mad_decoder_plugin.c", line 550: (enum) tag redeclared: version
 cc: acomp failed for src/decoder/mad_decoder_plugin.c
2010-12-21 07:57:07 +01:00
Alex Viskovatoff
144ad7992e output/solaris: add missing parameter to open_cloexec() call 2010-12-21 07:31:08 +01:00
Alex Viskovatoff
a0dd1a1b8b audio_check: fix parameter in prototype 2010-12-21 07:29:58 +01:00
Max Kellermann
c360e69162 Modify version string to post-release version 0.16.1~git 2010-12-21 07:29:31 +01:00
Avuton Olrich
da01c6ef5b mpd version 0.16 2010-12-11 04:19:49 -08:00
Max Kellermann
fcd2355f4f Merge branch 'master' of git://git.musicpd.org/avuton/mpd 2010-12-07 18:18:19 +01:00
Max Kellermann
748a8a6f42 tag_id3: support multiple values
Loop over all frames with a specific id, and import all of them - not
just the first one (index 0).
2010-12-07 18:05:44 +01:00
Anton Khirnov
cb9965bab5 command: don't error when sticker list is run on song with no stickers
this is inconsistent with other commands (e.g. find) and seems wrong --
a song with no stickers attached is a perfectly valid state and an empty
list of stickers is also perfectly valid.
2010-12-07 17:32:52 +01:00
Max Kellermann
429ed24c99 tag_ape: support multiple values
One APE tag may contain more than one value, separated by null bytes.
2010-11-24 08:59:04 +01:00
Max Kellermann
1ab46472ab decoder_thread: load APE replay gain from music files 2010-11-18 23:02:30 +01:00
Max Kellermann
f6bbe1332f replay_gain_ape: parse replay gain from APE tags
Based on the APE reader.
2010-11-18 22:26:06 +01:00
Max Kellermann
11613347be tag_ape: move code to ape.c
Generic library for scanning APE tags.  Eliminated one "goto"!
2010-11-18 21:44:24 +01:00
Max Kellermann
8f46f1520c timer: fix integer overflow in timer_delay()
Fixes a regression: for output_plugin.delay(), we added a method to
the timer class which returns the delay in milliseconds.  This fails
to detect negative values, because the unsigned integer is divided by
1000, and then casted to signed.
2010-11-18 21:29:03 +01:00
Avuton Olrich
f2893b0d0f Modify version string to post-release version 0.16~git 2010-11-08 18:57:09 -08:00
Avuton Olrich
c7265f9689 mpd version 0.16~alpha4 2010-11-08 18:57:09 -08:00
Max Kellermann
46ab8d18e2 playlist_song: calculate duration of last CUE track 2010-11-08 20:16:26 +01:00
Max Kellermann
f384f8da93 Merge release 0.15.15 from branch 'v0.15.x'
Conflicts:
	NEWS
	configure.ac
2010-11-08 18:50:22 +01:00
Max Kellermann
23cd8a74be mpd version 0.15.15 2010-11-08 18:48:28 +01:00
Max Kellermann
cc1debc948 output/shout: artist comes first in stream title
After popular demand, I've switched the order of "artist" and "title"
in the stream title.  There is no standard, and there is no reliable
way to parse those from the stream title.
2010-11-08 18:46:14 +01:00
Max Kellermann
5a3aa1262a update_walk: explicitly check for permission problems
Call access() and print an extra error message when EACCES is
returned.  Hopefully this will reduce the number of support requests
due to wrong file permissions.
2010-11-08 18:24:19 +01:00
Max Kellermann
ad52eb236d input/rewind: fix assertion failure
The assertion added in MPD 0.15.14 was too much, it failed when the
MIME type of a stream was NULL.
2010-11-08 10:37:09 +01:00
Avuton Olrich
d2c2cbd0ae Modify version string to post-release version 0.16~git 2010-11-07 06:39:31 -08:00
Avuton Olrich
462bba8e2f Modify version string to post-release version 0.15.15~git 2010-11-06 14:42:03 -07:00
50 changed files with 747 additions and 296 deletions

@@ -7,6 +7,8 @@ AM_CPPFLAGS += -DSYSTEM_CONFIG_FILE_LOCATION='"$(sysconfdir)/mpd.conf"'
bin_PROGRAMS = src/mpd
noinst_LIBRARIES =
src_mpd_CFLAGS = $(AM_CFLAGS) $(MPD_CFLAGS)
src_mpd_CPPFLAGS = $(AM_CPPFLAGS) \
$(LIBWRAP_CFLAGS) \
@@ -34,6 +36,7 @@ mpd_headers = \
src/check.h \
src/notify.h \
src/ack.h \
src/ape.h \
src/audio.h \
src/audio_format.h \
src/audio_check.h \
@@ -186,6 +189,7 @@ mpd_headers = \
src/refcount.h \
src/replay_gain_config.h \
src/replay_gain_info.h \
src/replay_gain_ape.h \
src/sig_handlers.h \
src/song.h \
src/song_print.h \
@@ -412,6 +416,8 @@ TAG_LIBS = \
$(ID3TAG_LIBS)
TAG_SRC = \
src/ape.c \
src/replay_gain_ape.c \
src/tag_ape.c
if HAVE_ID3TAG
@@ -428,7 +434,6 @@ DECODER_CFLAGS = \
$(SNDFILE_CFLAGS) \
$(AUDIOFILE_CFLAGS) \
$(LIBMIKMOD_CFLAGS) \
$(MODPLUG_CFLAGS) \
$(GME_CFLAGS) \
$(SIDPLAY_CFLAGS) \
$(FLUIDSYNTH_CFLAGS) \
@@ -444,7 +449,6 @@ DECODER_LIBS = \
$(FLAC_LIBS) \
$(SNDFILE_LIBS) \
$(AUDIOFILE_LIBS) $(LIBMIKMOD_LIBS) \
$(MODPLUG_LIBS) \
$(GME_LIBS) \
$(SIDPLAY_LIBS) \
$(FLUIDSYNTH_LIBS) \
@@ -517,7 +521,11 @@ DECODER_SRC += src/decoder/mikmod_decoder_plugin.c
endif
if HAVE_MODPLUG
DECODER_SRC += src/decoder/modplug_decoder_plugin.c
libmodplug_decoder_plugin_a_SOURCES = src/decoder/modplug_decoder_plugin.c
libmodplug_decoder_plugin_a_CFLAGS = $(src_mpd_CFLAGS) $(MODPLUG_CFLAGS)
libmodplug_decoder_plugin_a_CPPFLAGS = $(src_mpd_CPPFLAGS)
noinst_LIBRARIES += libmodplug_decoder_plugin.a
DECODER_LIBS += libmodplug_decoder_plugin.a $(MODPLUG_LIBS)
endif
if ENABLE_SIDPLAY
@@ -851,6 +859,7 @@ test_run_input_LDADD = $(MPD_LIBS) \
$(INPUT_LIBS) \
$(GLIB_LIBS)
test_run_input_SOURCES = test/run_input.c \
test/stdbin.h \
src/conf.c src/tokenizer.c src/utils.c \
src/tag.c src/tag_pool.c src/tag_save.c \
src/fd_util.c \
@@ -898,6 +907,7 @@ test_run_decoder_LDADD = $(MPD_LIBS) \
$(INPUT_LIBS) $(DECODER_LIBS) \
$(GLIB_LIBS)
test_run_decoder_SOURCES = test/run_decoder.c \
test/stdbin.h \
src/conf.c src/tokenizer.c src/utils.c src/log.c \
src/tag.c src/tag_pool.c \
src/replay_gain_info.c \
@@ -938,6 +948,7 @@ test_run_filter_LDADD = $(MPD_LIBS) \
$(SAMPLERATE_LIBS) \
$(GLIB_LIBS)
test_run_filter_SOURCES = test/run_filter.c \
test/stdbin.h \
src/filter_plugin.c \
src/filter_registry.c \
src/conf.c src/tokenizer.c src/utils.c \
@@ -960,6 +971,7 @@ endif
if ENABLE_ENCODER
noinst_PROGRAMS += test/run_encoder
test_run_encoder_SOURCES = test/run_encoder.c \
test/stdbin.h \
src/conf.c src/tokenizer.c \
src/utils.c \
src/tag.c src/tag_pool.c \
@@ -967,12 +979,15 @@ test_run_encoder_SOURCES = test/run_encoder.c \
src/audio_format.c \
src/audio_parser.c \
$(ENCODER_SRC)
test_run_encoder_CPPFLAGS = $(AM_CPPFLAGS) \
$(ENCODER_CFLAGS)
test_run_encoder_LDADD = $(MPD_LIBS) \
$(ENCODER_LIBS) \
$(GLIB_LIBS)
endif
test_software_volume_SOURCES = test/software_volume.c \
test/stdbin.h \
src/audio_check.c \
src/audio_parser.c \
src/pcm_volume.c
@@ -980,6 +995,7 @@ test_software_volume_LDADD = \
$(GLIB_LIBS)
test_run_normalize_SOURCES = test/run_normalize.c \
test/stdbin.h \
src/audio_check.c \
src/audio_parser.c \
src/AudioCompress/compress.c
@@ -1017,6 +1033,7 @@ test_run_output_LDADD = $(MPD_LIBS) \
$(OUTPUT_LIBS) \
$(GLIB_LIBS)
test_run_output_SOURCES = test/run_output.c \
test/stdbin.h \
src/conf.c src/tokenizer.c src/utils.c src/log.c \
src/audio_check.c \
src/audio_format.c \

68
NEWS

@@ -1,4 +1,44 @@
ver 0.16 (20??/??/??)
ver 0.16.3 (2011/06/04)
* fix assertion failure in audio format mask parser
* fix NULL pointer dereference in playlist parser
* fix playlist files in base music directory
* database: allow directories with just playlists
* decoder:
- ffmpeg: support libavcodec 0.7
ver 0.16.2 (2011/03/18)
* configure.ac:
- fix bashism in tremor test
* decoder:
- tremor: fix configure test
- gme: detect end of song
* encoder:
- vorbis: reset the Ogg stream after flush
* output:
- httpd: fix uninitialized variable
- httpd: include sys/socket.h
- oss: AFMT_S24_PACKED is little-endian
- oss: disable 24 bit playback on FreeBSD
ver 0.16.1 (2011/01/09)
* audio_check: fix parameter in prototype
* add void casts to suppress "result unused" warnings (clang)
* input:
- ffado: disable by default
* decoder:
- mad: work around build failure on Solaris
- resolve modplug vs. libsndfile cflags/headers conflict
* output:
- solaris: add missing parameter to open_cloexec() cal
- osx: fix up audio format first, then apply it to device
* player_thread: discard empty chunks while cross-fading
* player_thread: fix assertion failure due to early seek
* output_thread: fix double lock
ver 0.16 (2010/12/11)
* protocol:
- send song modification time to client
- added "update" idle event
@@ -20,7 +60,9 @@ ver 0.16 (20??/??/??)
* tags:
- added tags "ArtistSort", "AlbumArtistSort"
- id3: revised "performer" tag support
- id3: support multiple values
- ape: MusicBrainz tags
- ape: support multiple values
* decoders:
- don't try a plugin twice (MIME type & suffix)
- don't fall back to "mad" unless no plugin matches
@@ -88,6 +130,7 @@ ver 0.16 (20??/??/??)
- fall back to track gain if album gain is unavailable
- optionally use hardware mixer to apply replay gain
- added mode "auto"
- parse replay gain from APE tags
* log unused/unknown block parameters
* removed the deprecated "error_file" option
* save state when stopped
@@ -109,6 +152,29 @@ ver 0.16 (20??/??/??)
* make single mode 'sticky'
ver 0.15.17 (2011/??/??)
* encoder:
- vorbis: reset the Ogg stream after flush
* decoders:
- vorbis: fix tremor support
ver 0.15.16 (2011/03/13)
* output:
- ao: initialize the ao_sample_format struct
- jack: fix crash with mono playback
* encoders:
- lame: explicitly configure the output sample rate
* update: log all file permission problems
ver 0.15.15 (2010/11/08)
* input:
- rewind: fix assertion failure
* output:
- shout: artist comes first in stream title
ver 0.15.14 (2010/11/06)
* player_thread: fix assertion failure due to wrong music pipe on seek
* output_thread: fix assertion failure due to race condition in OPEN

@@ -1,5 +1,5 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.16~alpha3, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.16.3, musicpd-dev-team@lists.sourceforge.net)
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
AM_CONFIG_HEADER(config.h)
@@ -13,6 +13,7 @@ dnl Programs
dnl ---------------------------------------------------------------------------
AC_PROG_CC_C99
AC_PROG_CXX
AC_PROG_RANLIB
HAVE_CXX=yes
if test x$CXX = xg++; then
@@ -157,7 +158,7 @@ AC_ARG_ENABLE(documentation,
AC_ARG_ENABLE(ffado,
AS_HELP_STRING([--enable-ffado], [enable libffado (FireWire) support]),,
[enable_ffado=auto])
[enable_ffado=no])
AC_ARG_ENABLE(ffmpeg,
AS_HELP_STRING([--enable-ffmpeg],
@@ -634,7 +635,7 @@ fi
AM_CONDITIONAL(ENABLE_LASTFM, test x$enable_lastfm = xyes)
dnl ---------------------------------- libogg ---------------------------------
if test x$with_tremor == xno || test -z $with_tremor; then
if test x$with_tremor = xno || test -z $with_tremor; then
PKG_CHECK_MODULES(OGG, [ogg], enable_ogg=yes, enable_ogg=no)
fi
@@ -849,15 +850,6 @@ if test x$enable_modplug = xyes; then
fi
AM_CONDITIONAL(HAVE_MODPLUG, test x$enable_modplug = xyes)
dnl --------------------------- sndfile/modplug test --------------------------
if test x$enable_sndfile = xauto && test x$enable_modplug = xyes; then
dnl If modplug is enabled, enable sndfile only if explicitly
dnl requested - modplug's modplug/sndfile.h is known to
dnl conflict with libsndfile's sndfile.h.
AC_MSG_NOTICE([disabling libsndfile auto-detection, because the modplug decoder is enabled])
enable_sndfile=no
fi
dnl -------------------------------- libsndfile -------------------------------
dnl See above test, which may disable this.
MPD_AUTO_PKG(sndfile, SNDFILE, [sndfile],
@@ -942,13 +934,19 @@ if test x$enable_tremor = xyes; then
ac_save_LIBS="$LIBS"
CFLAGS="$CFLAGS $TREMOR_CFLAGS"
LIBS="$LIBS $TREMOR_LIBS"
AC_CHECK_LIB(vorbisidec,ov_read,enable_vorbis=yes,enable_vorbis=no;
AC_CHECK_LIB(vorbisidec,ov_read,,enable_tremor=no;
AC_MSG_WARN([vorbisidec lib needed for ogg support with tremor -- disabling ogg support]))
CFLAGS="$ac_save_CFLAGS"
LIBS="$ac_save_LIBS"
fi
if test x$enable_tremor = xyes; then
AC_DEFINE(HAVE_TREMOR,1,
[Define to use tremor (libvorbisidec) for ogg support])
AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]),
else
TREMOR_CFLAGS=
TREMOR_LIBS=
fi
AC_SUBST(TREMOR_CFLAGS)
@@ -988,7 +986,7 @@ if test x$enable_vorbis = xyes; then
fi
fi
AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes)
AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes)
dnl --------------------------------- sidplay ---------------------------------
found_sidplay=$HAVE_CXX
@@ -1083,7 +1081,7 @@ if
fi
AM_CONDITIONAL(HAVE_OGG_COMMON,
test x$enable_vorbis = xyes || test x$enable_oggflac = xyes || test x$enable_flac = xyes)
test x$enable_vorbis = xyes || test x$enable_tremor = xyes || test x$enable_oggflac = xyes || test x$enable_flac = xyes)
AM_CONDITIONAL(HAVE_FLAC_COMMON,
test x$enable_flac = xyes || test x$enable_oggflac = xyes)
@@ -1495,23 +1493,23 @@ dnl ---------------------------------------------------------------------------
echo ''
echo '########### MPD CONFIGURATION ############'
echo -ne '\nArchive support:\n\t'
printf '\nArchive support:\n\t'
results(bzip2,[bzip2])
results(iso9660,[ISO9660])
results(zzip,[ZIP])
if test x$with_zeroconf != xno; then
echo -ne '\nAutodiscovery support:\n\t'
printf '\nAutodiscovery support:\n\t'
results(avahi, [Avahi])
results(bonjour, [Bonjour])
fi
echo -ne '\nClient support:\n\t'
printf '\nClient support:\n\t'
results(ipv6, "IPv6")
results(tcp, "TCP")
results(un,[UNIX Domain Sockets])
echo -ne '\nFile format support:\n\t'
printf '\nFile format support:\n\t'
results(aac, [AAC])
results(sidplay, [C64 SID])
results(ffmpeg, [FFMPEG])
@@ -1519,7 +1517,7 @@ results(flac, [FLAC])
results(fluidsynth, [FluidSynth])
results(gme, [GME])
results(sndfile, [libsndfile])
echo -ne '\n\t'
printf '\n\t'
results(mikmod, [MikMod])
results(modplug, [MODPLUG])
results(mad, [MAD])
@@ -1527,23 +1525,23 @@ results(mpg123, [MPG123])
results(mp4, [MP4])
results(mpc, [Musepack])
results(oggflac, [OggFLAC], flac)
echo -ne '\n\t'
printf '\n\t'
results(tremor, [OggTremor])
results(vorbis, [OggVorbis])
results(audiofile, [WAVE])
results(wavpack, [WavPack])
results(wildmidi, [WildMidi])
echo -en '\nOther features:\n\t'
printf '\nOther features:\n\t'
results(lsr, [libsamplerate])
results(inotify, [inotify])
results(sqlite, [SQLite])
echo -en '\nMetadata support:\n\t'
printf '\nMetadata support:\n\t'
results(cue,[cue])
results(id3,[ID3])
echo -en '\nPlayback support:\n\t'
printf '\nPlayback support:\n\t'
results(alsa,ALSA)
results(ffado,FFADO)
results(fifo,FIFO)
@@ -1552,14 +1550,14 @@ results(httpd_output,[HTTP Daemon])
results(jack,[JACK])
results(ao,[libao])
results(oss,[OSS])
echo -ne '\n\t'
printf '\n\t'
results(openal,[OpenAL])
results(osx, [OS X])
results(pipe_output, [Pipeline])
results(pulse, [PulseAudio])
results(mvp, [Media MVP])
results(shout, [SHOUTcast])
echo -ne '\n\t'
printf '\n\t'
results(solaris, [Solaris])
results(winmm_output, [WinMM])
@@ -1567,7 +1565,7 @@ if
test x$enable_shout = xyes ||
test x$enable_recorder = xyes ||
test x$enable_httpd_output = xyes; then
echo -en '\nStreaming encoder support:\n\t'
printf '\nStreaming encoder support:\n\t'
results(flac_encoder, [FLAC])
results(lame_encoder, [LAME])
results(vorbis_encoder, [Ogg Vorbis])
@@ -1575,19 +1573,14 @@ if
results(wave_encoder, [WAVE])
fi
echo -en '\nStreaming support:\n\t'
printf '\nStreaming support:\n\t'
results(curl,[CURL])
results(lastfm,[Last.FM])
results(mms,[MMS])
echo -ne '\n\n##########################################\n\n'
printf '\n\n##########################################\n\n'
if test x$enable_sndfile = xyes && test x$enable_modplug = xyes; then
AC_MSG_WARN([compilation may fail, because libmodplug conflicts with libsndfile])
AC_MSG_WARN([libmodplug ships modplug/sndfile.h, which hides libsndfile's sndfile.h])
fi
echo -ne 'Generating files needed for compilation\n'
echo 'Generating files needed for compilation'
dnl ---------------------------------------------------------------------------
dnl Generate files

@@ -58,7 +58,7 @@ if test x$enable_aac = xyes; then
fi
if test x$enable_aac = xyes; then
AC_MSG_CHECKING(that FAAD2 uses buffer and bufferlen)
AC_COMPILE_IFELSE([
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
int main() {
@@ -82,9 +82,9 @@ int main() {
return 0;
}
],[AC_MSG_RESULT(yes);AC_DEFINE(HAVE_FAAD_BUFLEN_FUNCS,1,[Define if FAAD2 uses buflen in function calls])],[AC_MSG_RESULT(no);
])],[AC_MSG_RESULT(yes);AC_DEFINE(HAVE_FAAD_BUFLEN_FUNCS,1,[Define if FAAD2 uses buflen in function calls])],[AC_MSG_RESULT(no);
AC_MSG_CHECKING(that FAAD2 can even be used)
AC_COMPILE_IFELSE([
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
int main() {
@@ -113,7 +113,7 @@ int main() {
return 0;
}
],AC_MSG_RESULT(yes),[AC_MSG_RESULT(no);enable_aac=no])
])],AC_MSG_RESULT(yes),[AC_MSG_RESULT(no);enable_aac=no])
])
fi
if test x$enable_aac = xyes; then
@@ -136,7 +136,7 @@ if test x$enable_aac = xyes; then
CPPFLAGS=$CFLAGS
AC_MSG_CHECKING(for broken libfaad headers)
AC_COMPILE_IFELSE([
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
#include <faad.h>
#include <stddef.h>
#include <stdint.h>
@@ -148,7 +148,7 @@ int main() {
faacDecInit2(NULL, NULL, 0, &sample_rate, &channels);
return 0;
}
],
])],
[AC_MSG_RESULT(correct)],
[AC_MSG_RESULT(broken);
AC_DEFINE(HAVE_FAAD_LONG, 1, [Define if faad.h uses the broken "unsigned long" pointers])])

@@ -4,9 +4,9 @@ AC_DEFUN([MPD_CHECK_FLAG],[
[mpd_check_cflag_$var],[
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_COMPILE_IFELSE([
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
int main(void) { return 0; }
], [ eval "mpd_check_cflag_$var=yes"
])], [ eval "mpd_check_cflag_$var=yes"
], [ eval "mpd_check_cflag_$var=no" ])
CFLAGS="$save_CFLAGS"
])

@@ -1,19 +1,19 @@
AC_DEFUN([results], [
dnl This is a hack to allow "with" names, otherwise "enable".
num=`expr match $1 'with'`
num=`expr $1 : 'with'`
if test "$num" != "0"; then
var="`echo '$'$1`"
else
var="`echo '$'enable_$1`"
fi
echo -n '('
printf '('
if eval "test x$var = xyes"; then
echo -n '+'
printf '+'
elif test -n "$3" && eval "test x$var = x$3"; then
echo -n '+'
printf '+'
else
echo -n '-'
printf '-'
fi
echo -n "$2) "
printf '%s) ' "$2"
])

@@ -16,16 +16,16 @@
struct Compressor {
//! The compressor's preferences
struct CompressorConfig prefs;
//! History of the peak values
int *peaks;
//! History of the gain values
int *gain;
//! History of clip amounts
int *clipped;
unsigned int pos;
unsigned int bufsz;
};
@@ -41,9 +41,9 @@ struct Compressor *Compressor_new(unsigned int history)
obj->peaks = obj->gain = obj->clipped = NULL;
obj->bufsz = 0;
obj->pos = 0;
Compressor_setHistory(obj, history);
return obj;
}
@@ -70,7 +70,7 @@ void Compressor_setHistory(struct Compressor *obj, unsigned int history)
{
if (!history)
history = BUCKETS;
obj->peaks = resizeArray(obj->peaks, history, obj->bufsz);
obj->gain = resizeArray(obj->gain, history, obj->bufsz);
obj->clipped = resizeArray(obj->clipped, history, obj->bufsz);
@@ -82,7 +82,7 @@ struct CompressorConfig *Compressor_getConfig(struct Compressor *obj)
return &obj->prefs;
}
void Compressor_Process_int16(struct Compressor *obj, int16_t *audio,
void Compressor_Process_int16(struct Compressor *obj, int16_t *audio,
unsigned int count)
{
struct CompressorConfig *prefs = Compressor_getConfig(obj);
@@ -97,7 +97,7 @@ void Compressor_Process_int16(struct Compressor *obj, int16_t *audio,
int *clipped = obj->clipped + slot;
unsigned int ramp = count;
int delta;
ap = audio;
for (i = 0; i < count; i++)
{
@@ -124,15 +124,15 @@ void Compressor_Process_int16(struct Compressor *obj, int16_t *audio,
//! Determine target gain
newGain = (1 << 10)*prefs->target/peakVal;
//! Adjust the gain with inertia from the previous gain value
newGain = (curGain*((1 << prefs->smooth) - 1) + newGain)
newGain = (curGain*((1 << prefs->smooth) - 1) + newGain)
>> prefs->smooth;
//! Make sure it's no more than the maximum gain value
if (newGain > (prefs->maxgain << 10))
newGain = prefs->maxgain << 10;
//! Make sure it's no less than 1:1
if (newGain < (1 << 10))
newGain = 1 << 10;
@@ -144,7 +144,7 @@ void Compressor_Process_int16(struct Compressor *obj, int16_t *audio,
//! Truncate the ramp time
ramp = peakPos;
}
//! Record the new gain
obj->gain[slot] = newGain;

113
src/ape.c Normal file

@@ -0,0 +1,113 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "ape.h"
#include <glib.h>
#include <stdint.h>
#include <assert.h>
#include <stdio.h>
#include <string.h>
struct ape_footer {
unsigned char id[8];
uint32_t version;
uint32_t length;
uint32_t count;
unsigned char flags[4];
unsigned char reserved[8];
};
static bool
ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx)
{
/* determine if file has an apeV2 tag */
struct ape_footer footer;
if (fseek(fp, -(long)sizeof(footer), SEEK_END) ||
fread(&footer, 1, sizeof(footer), fp) != sizeof(footer) ||
memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0 ||
GUINT32_FROM_LE(footer.version) != 2000)
return false;
/* find beginning of ape tag */
size_t remaining = GUINT32_FROM_LE(footer.length);
if (remaining <= sizeof(footer) + 10 ||
/* refuse to load more than one megabyte of tag data */
remaining > 1024 * 1024 ||
fseek(fp, -(long)remaining, SEEK_END))
return false;
/* read tag into buffer */
remaining -= sizeof(footer);
assert(remaining > 10);
char *buffer = g_malloc(remaining);
if (fread(buffer, 1, remaining, fp) != remaining)
return false;
/* read tags */
unsigned n = GUINT32_FROM_LE(footer.count);
const char *p = buffer;
while (n-- && remaining > 10) {
size_t size = GUINT32_FROM_LE(*(const uint32_t *)p);
p += 4;
remaining -= 4;
unsigned long flags = GUINT32_FROM_LE(*(const uint32_t *)p);
p += 4;
remaining -= 4;
/* get the key */
const char *key = p;
while (remaining > size && *p != '\0') {
p++;
remaining--;
}
p++;
remaining--;
/* get the value */
if (remaining < size)
break;
if (!callback(flags, key, p, size, ctx))
break;
p += size;
remaining -= size;
}
g_free(buffer);
return true;
}
bool
tag_ape_scan(const char *path_fs, tag_ape_callback_t callback, void *ctx)
{
FILE *fp;
fp = fopen(path_fs, "rb");
if (fp == NULL)
return false;
bool success = ape_scan_internal(fp, callback, ctx);
fclose(fp);
return success;
}

42
src/ape.h Normal file

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_APE_H
#define MPD_APE_H
#include "check.h"
#include <stdbool.h>
#include <stddef.h>
typedef bool (*tag_ape_callback_t)(unsigned long flags, const char *key,
const char *value, size_t value_length,
void *ctx);
/**
* Scans the APE tag values from a file.
*
* @param path_fs the path of the file in filesystem encoding
* @return false if the file could not be opened or if no APE tag is
* present
*/
bool
tag_ape_scan(const char *path_fs, tag_ape_callback_t callback, void *ctx);
#endif

@@ -38,7 +38,7 @@ bool
audio_check_sample_rate(unsigned long sample_rate, GError **error_r);
bool
audio_check_sample_format(unsigned sample_format, GError **error_r);
audio_check_sample_format(enum sample_format, GError **error_r);
bool
audio_check_channel_count(unsigned sample_format, GError **error_r);

@@ -22,6 +22,7 @@
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
enum sample_format {
SAMPLE_FORMAT_UNDEFINED = 0,
@@ -219,6 +220,9 @@ static inline void
audio_format_mask_apply(struct audio_format *af,
const struct audio_format *mask)
{
assert(audio_format_valid(af));
assert(audio_format_mask_valid(mask));
if (mask->sample_rate != 0)
af->sample_rate = mask->sample_rate;
@@ -227,6 +231,8 @@ audio_format_mask_apply(struct audio_format *af,
if (mask->channels != 0)
af->channels = mask->channels;
assert(audio_format_valid(af));
}
/**

@@ -192,6 +192,8 @@ audio_format_parse(struct audio_format *dest, const char *src,
}
audio_format_init(dest, rate, sample_format, channels);
assert(mask ? audio_format_mask_valid(dest)
: audio_format_valid(dest));
return true;
}

@@ -464,7 +464,7 @@ handle_currentsong(struct client *client,
G_GNUC_UNUSED int argc, G_GNUC_UNUSED char *argv[])
{
playlist_print_current(client, &g_playlist);
return PLAYLIST_RESULT_SUCCESS;
return COMMAND_RETURN_OK;
}
static enum command_return
@@ -749,7 +749,7 @@ handle_load(struct client *client, G_GNUC_UNUSED int argc, char *argv[])
result = playlist_open_into_queue(argv[1], &g_playlist);
if (result != PLAYLIST_RESULT_NO_SUCH_LIST)
return result;
return print_playlist_result(client, result);
result = playlist_load_spl(&g_playlist, argv[1]);
return print_playlist_result(client, result);
@@ -1715,15 +1715,11 @@ handle_sticker_song(struct client *client, int argc, char *argv[])
}
sticker = sticker_song_get(song);
if (NULL == sticker) {
command_error(client, ACK_ERROR_NO_EXIST,
"no stickers found");
return COMMAND_RETURN_ERROR;
if (sticker) {
sticker_print(client, sticker);
sticker_free(sticker);
}
sticker_print(client, sticker);
sticker_free(sticker);
return COMMAND_RETURN_OK;
/* set song song_id id key */
} else if (argc == 6 && strcmp(argv[1], "set") == 0) {

@@ -244,7 +244,7 @@ static const char *const audiofile_suffixes[] = {
static const char *const audiofile_mime_types[] = {
"audio/x-wav",
"audio/x-aiff",
NULL
NULL
};
const struct decoder_plugin audiofile_decoder_plugin = {

@@ -81,6 +81,10 @@ mpd_ffmpeg_log_callback(G_GNUC_UNUSED void *ptr, int level,
#endif /* !OLD_FFMPEG_INCLUDES */
#ifndef AV_VERSION_INT
#define AV_VERSION_INT(a, b, c) (a<<16 | b<<8 | c)
#endif
struct mpd_ffmpeg_stream {
struct decoder *decoder;
struct input_stream *input;
@@ -102,13 +106,11 @@ static int64_t
mpd_ffmpeg_stream_seek(void *opaque, int64_t pos, int whence)
{
struct mpd_ffmpeg_stream *stream = opaque;
bool ret;
if (whence == AVSEEK_SIZE)
return stream->input->size;
ret = input_stream_seek(stream->input, pos, whence, NULL);
if (!ret)
if (!input_stream_seek(stream->input, pos, whence, NULL))
return -1;
return stream->input->offset;
@@ -156,7 +158,11 @@ ffmpeg_find_audio_stream(const AVFormatContext *format_context)
{
for (unsigned i = 0; i < format_context->nb_streams; ++i)
if (format_context->streams[i]->codec->codec_type ==
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52, 64, 0)
AVMEDIA_TYPE_AUDIO)
#else
CODEC_TYPE_AUDIO)
#endif
return i;
return -1;
@@ -183,30 +189,40 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
AVCodecContext *codec_context,
const AVRational *time_base)
{
enum decoder_command cmd = DECODE_COMMAND_NONE;
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16];
int16_t *aligned_buffer;
size_t buffer_size;
int len, audio_size;
uint8_t *packet_data;
int packet_size;
if (packet->pts != (int64_t)AV_NOPTS_VALUE)
decoder_timestamp(decoder,
av_rescale_q(packet->pts, *time_base,
(AVRational){1, 1}));
packet_data = packet->data;
packet_size = packet->size;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,25,0)
AVPacket packet2 = *packet;
#else
const uint8_t *packet_data = packet->data;
int packet_size = packet->size;
#endif
buffer_size = sizeof(audio_buf);
aligned_buffer = align16(audio_buf, &buffer_size);
uint8_t audio_buf[(AVCODEC_MAX_AUDIO_FRAME_SIZE * 3) / 2 + 16];
size_t buffer_size = sizeof(audio_buf);
int16_t *aligned_buffer = align16(audio_buf, &buffer_size);
while ((packet_size > 0) && (cmd == DECODE_COMMAND_NONE)) {
audio_size = buffer_size;
len = avcodec_decode_audio2(codec_context,
aligned_buffer, &audio_size,
packet_data, packet_size);
enum decoder_command cmd = DECODE_COMMAND_NONE;
while (
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,25,0)
packet2.size > 0 &&
#else
packet_size > 0 &&
#endif
cmd == DECODE_COMMAND_NONE) {
int audio_size = buffer_size;
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,25,0)
int len = avcodec_decode_audio3(codec_context,
aligned_buffer, &audio_size,
&packet2);
#else
int len = avcodec_decode_audio2(codec_context,
aligned_buffer, &audio_size,
packet_data, packet_size);
#endif
if (len < 0) {
/* if error, we skip the frame */
@@ -214,8 +230,13 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
break;
}
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(52,25,0)
packet2.data += len;
packet2.size -= len;
#else
packet_data += len;
packet_size -= len;
#endif
if (audio_size <= 0)
continue;
@@ -230,7 +251,7 @@ ffmpeg_send_packet(struct decoder *decoder, struct input_stream *is,
static enum sample_format
ffmpeg_sample_format(G_GNUC_UNUSED const AVCodecContext *codec_context)
{
#if LIBAVCODEC_VERSION_INT >= ((51<<16)+(41<<8)+0)
#if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT(51, 41, 0)
switch (codec_context->sample_fmt) {
case SAMPLE_FMT_S16:
return SAMPLE_FORMAT_S16;
@@ -299,12 +320,8 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
return;
}
AVFormatContext *format_context;
AVCodecContext *codec_context;
AVCodec *codec;
int audio_stream;
//ffmpeg works with ours "fileops" helper
AVFormatContext *format_context;
if (av_open_input_stream(&format_context, stream->io, input->uri,
input_format, NULL) != 0) {
g_warning("Open failed\n");
@@ -319,7 +336,7 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
return;
}
audio_stream = ffmpeg_find_audio_stream(format_context);
int audio_stream = ffmpeg_find_audio_stream(format_context);
if (audio_stream == -1) {
g_warning("No audio stream inside\n");
av_close_input_stream(format_context);
@@ -327,11 +344,12 @@ ffmpeg_decode(struct decoder *decoder, struct input_stream *input)
return;
}
codec_context = format_context->streams[audio_stream]->codec;
AVCodecContext *codec_context =
format_context->streams[audio_stream]->codec;
if (codec_context->codec_name[0] != 0)
g_debug("codec '%s'", codec_context->codec_name);
codec = avcodec_find_decoder(codec_context->codec_id);
AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);
if (!codec) {
g_warning("Unsupported audio codec\n");

@@ -81,7 +81,7 @@ flac_tell_cb(G_GNUC_UNUSED const FLAC__StreamDecoder *fd,
struct flac_data *data = (struct flac_data *) fdata;
if (!data->input_stream->seekable)
return FLAC__STREAM_DECODER_SEEK_STATUS_UNSUPPORTED;
return FLAC__STREAM_DECODER_TELL_STATUS_UNSUPPORTED;
*offset = (long)(data->input_stream->offset);

@@ -153,6 +153,9 @@ gme_file_decode(struct decoder *decoder, const char *path_fs)
if((gme_err = gme_start_track(emu, song_num)) != NULL)
g_warning("%s", gme_err);
if(ti->length > 0)
gme_set_fade(emu, ti->length);
/* play */
do {
gme_err = gme_play(emu, GME_BUFFER_SAMPLES, buf);

@@ -547,14 +547,14 @@ enum {
XING_SCALE = 0x00000008L
};
struct version {
struct lame_version {
unsigned major;
unsigned minor;
};
struct lame {
char encoder[10]; /* 9 byte encoder name/version ("LAME3.97b") */
struct version version; /* struct containing just the version */
struct lame_version version; /* struct containing just the version */
float peak; /* replaygain peak */
float track_gain; /* replaygain track gain */
float album_gain; /* replaygain album gain */

@@ -24,6 +24,7 @@
#include "decoder_list.h"
#include "decoder_plugin.h"
#include "decoder_api.h"
#include "replay_gain_ape.h"
#include "input_stream.h"
#include "player_control.h"
#include "pipe.h"
@@ -297,6 +298,18 @@ decoder_run_stream(struct decoder *decoder, const char *uri)
return success;
}
/**
* Attempt to load replay gain data, and pass it to
* decoder_replay_gain().
*/
static void
decoder_load_replay_gain(struct decoder *decoder, const char *path_fs)
{
struct replay_gain_info info;
if (replay_gain_ape_read(path_fs, &info))
decoder_replay_gain(decoder, &info);
}
/**
* Try decoding a file.
*/
@@ -312,6 +325,8 @@ decoder_run_file(struct decoder *decoder, const char *path_fs)
decoder_unlock(dc);
decoder_load_replay_gain(decoder, path_fs);
while ((plugin = decoder_plugin_from_suffix(suffix, plugin)) != NULL) {
if (plugin->file_decode != NULL) {
decoder_lock(dc);

@@ -30,8 +30,8 @@
#define DIRECTORY_DIR "directory: "
#define DEVICE_INARCHIVE (dev_t)(-1)
#define DEVICE_CONTAINER (dev_t)(-2)
#define DEVICE_INARCHIVE (dev_t)(-1)
#define DEVICE_CONTAINER (dev_t)(-2)
struct directory {
struct dirvec children;
@@ -62,7 +62,8 @@ directory_free(struct directory *directory);
static inline bool
directory_is_empty(const struct directory *directory)
{
return directory->children.nr == 0 && directory->songs.nr == 0;
return directory->children.nr == 0 && directory->songs.nr == 0 &&
playlist_vector_is_empty(&directory->playlists);
}
static inline const char *

@@ -55,7 +55,7 @@ static bool
flac_encoder_configure(struct flac_encoder *encoder,
const struct config_param *param, G_GNUC_UNUSED GError **error)
{
encoder->compression = config_get_block_unsigned(param,
encoder->compression = config_get_block_unsigned(param,
"compression", 5);
return true;
@@ -218,7 +218,7 @@ flac_encoder_open(struct encoder *_encoder, struct audio_format *audio_format,
if (init_status != FLAC__STREAM_ENCODER_OK) {
g_set_error(error, flac_encoder_quark(), 0,
"failed to initialize encoder: %s\n",
"failed to initialize encoder: %s\n",
FLAC__StreamEncoderStateString[init_status]);
flac_encoder_close(_encoder);
return false;
@@ -234,7 +234,7 @@ flac_encoder_open(struct encoder *_encoder, struct audio_format *audio_format,
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
g_set_error(error, flac_encoder_quark(), 0,
"failed to initialize encoder: %s\n",
"failed to initialize encoder: %s\n",
FLAC__StreamEncoderInitStatusString[init_status]);
flac_encoder_close(_encoder);
return false;

@@ -170,6 +170,13 @@ lame_encoder_setup(struct lame_encoder *encoder, GError **error)
return false;
}
if (0 != lame_set_out_samplerate(encoder->gfp,
encoder->audio_format.sample_rate)) {
g_set_error(error, lame_encoder_quark(), 0,
"error setting lame out sample rate");
return false;
}
if (0 > lame_init_params(encoder->gfp)) {
g_set_error(error, lame_encoder_quark(), 0,
"error initializing lame params");

@@ -276,6 +276,8 @@ vorbis_encoder_flush(struct encoder *_encoder, G_GNUC_UNUSED GError **error)
vorbis_analysis_init(&encoder->vd, &encoder->vi);
vorbis_block_init(&encoder->vd, &encoder->vb);
ogg_stream_reset(&encoder->os);
encoder->flush = true;
return true;
}

@@ -58,7 +58,7 @@ wave_encoder_quark(void)
}
static void
fill_wave_header(struct wave_header *header, int channels, int bits,
fill_wave_header(struct wave_header *header, int channels, int bits,
int freq, int block_size)
{
int data_size = 0x0FFFFFFF;
@@ -142,7 +142,7 @@ wave_encoder_open(struct encoder *_encoder,
buffer = pcm_buffer_get(&encoder->buffer, sizeof(struct wave_header) );
/* create PCM wave header in initial buffer */
fill_wave_header((struct wave_header *) buffer,
fill_wave_header((struct wave_header *) buffer,
audio_format->channels,
encoder->bits,
audio_format->sample_rate,

@@ -81,7 +81,7 @@ copy_attributes(struct input_rewind *r)
const struct input_stream *src = r->input;
assert(dest != src);
assert(dest->mime != src->mime);
assert(src->mime == NULL || dest->mime != src->mime);
dest->ready = src->ready;
dest->seekable = src->seekable;

@@ -58,11 +58,11 @@ winmm_mixer_init(void *ao, G_GNUC_UNUSED const struct config_param *param,
G_GNUC_UNUSED GError **error_r)
{
assert(ao != NULL);
struct winmm_mixer *wm = g_new(struct winmm_mixer, 1);
mixer_init(&wm->base, &winmm_mixer_plugin);
wm->output = (struct winmm_output *) ao;
return &wm->base;
}
@@ -79,13 +79,13 @@ winmm_mixer_get_volume(struct mixer *mixer, GError **error_r)
DWORD volume;
HWAVEOUT handle = winmm_output_get_handle(wm->output);
MMRESULT result = waveOutGetVolume(handle, &volume);
if (result != MMSYSERR_NOERROR) {
g_set_error(error_r, 0, winmm_mixer_quark(),
"Failed to get winmm volume");
return -1;
}
return winmm_volume_decode(volume);
}
@@ -102,7 +102,7 @@ winmm_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
"Failed to set winmm volume");
return false;
}
return true;
}

@@ -26,6 +26,9 @@
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "ao"
/* An ao_sample_format, with all fields set to zero: */
static const ao_sample_format OUR_AO_FORMAT_INITIALIZER;
static unsigned ao_output_ref;
struct ao_data {
@@ -167,7 +170,7 @@ static bool
ao_output_open(void *data, struct audio_format *audio_format,
GError **error)
{
ao_sample_format format;
ao_sample_format format = OUR_AO_FORMAT_INITIALIZER;
struct ao_data *ad = (struct ao_data *)data;
switch (audio_format->format) {

@@ -29,6 +29,9 @@
#include <assert.h>
#include <string.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "httpd_output"
struct httpd_client {
/**
* The httpd output object this client is connected to.

@@ -111,7 +111,7 @@ struct httpd_output {
char buffer[32768];
/**
* The maximum and current number of clients connected
* The maximum and current number of clients connected
* at the same time.
*/
guint clients_max, clients_cnt;

@@ -36,6 +36,7 @@
#include <errno.h>
#ifdef HAVE_LIBWRAP
#include <sys/socket.h> /* needed for AF_UNIX */
#include <tcpd.h>
#endif
@@ -123,6 +124,7 @@ httpd_output_init(G_GNUC_UNUSED const struct audio_format *audio_format,
/* initialize metadata */
httpd->metadata = NULL;
httpd->unflushed_input = 0;
/* initialize encoder */

@@ -40,7 +40,7 @@ enum {
MAX_PORTS = 16,
};
static const size_t sample_size = sizeof(jack_default_audio_sample_t);
static const size_t jack_sample_size = sizeof(jack_default_audio_sample_t);
struct jack_data {
/**
@@ -103,9 +103,9 @@ mpd_jack_available(const struct jack_data *jd)
min = current;
}
assert(min % sample_size == 0);
assert(min % jack_sample_size == 0);
return min / sample_size;
return min / jack_sample_size;
}
static int
@@ -123,7 +123,7 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
const jack_nframes_t available = mpd_jack_available(jd);
for (unsigned i = 0; i < jd->audio_format.channels; ++i)
jack_ringbuffer_read_advance(jd->ringbuffer[i],
available * sample_size);
available * jack_sample_size);
/* generate silence while MPD is paused */
@@ -144,7 +144,7 @@ mpd_jack_process(jack_nframes_t nframes, void *arg)
for (unsigned i = 0; i < jd->audio_format.channels; ++i) {
out = jack_port_get_buffer(jd->ports[i], nframes);
jack_ringbuffer_read(jd->ringbuffer[i],
(char *)out, available * sample_size);
(char *)out, available * jack_sample_size);
for (jack_nframes_t f = available; f < nframes; ++f)
/* ringbuffer underrun, fill with silence */
@@ -675,7 +675,7 @@ mpd_jack_play(void *data, const void *chunk, size_t size, GError **error_r)
space = space1;
}
if (space >= frame_size)
if (space >= jack_sample_size)
break;
/* XXX do something more intelligent to
@@ -683,7 +683,7 @@ mpd_jack_play(void *data, const void *chunk, size_t size, GError **error_r)
g_usleep(1000);
}
space /= sample_size;
space /= jack_sample_size;
if (space < size)
size = space;

@@ -17,7 +17,7 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
/*
/*
* Media MVP audio output based on code from MVPMC project:
* http://mvpmc.sourceforge.net/
*/

@@ -41,6 +41,15 @@
# include <sys/soundcard.h>
#endif /* !(defined(__OpenBSD__) || defined(__NetBSD__) */
/* We got bug reports from FreeBSD users who said that the two 24 bit
formats generate white noise on FreeBSD, but 32 bit works. This is
a workaround until we know what exactly is expected by the kernel
audio drivers. */
#ifndef __linux__
#undef AFMT_S24_PACKED
#undef AFMT_S24_NE
#endif
struct oss_data {
int fd;
const char *device;
@@ -347,7 +356,7 @@ oss_setup_sample_rate(int fd, struct audio_format *audio_format,
case SUCCESS:
if (!audio_valid_sample_rate(sample_rate))
break;
audio_format->sample_rate = sample_rate;
return true;
@@ -461,6 +470,12 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
break;
audio_format->format = mpd_format;
#ifdef AFMT_S24_PACKED
if (oss_format == AFMT_S24_PACKED)
audio_format->reverse_endian =
G_BYTE_ORDER != G_LITTLE_ENDIAN;
#endif
return true;
case ERROR:
@@ -502,6 +517,12 @@ oss_setup_sample_format(int fd, struct audio_format *audio_format,
break;
audio_format->format = mpd_format;
#ifdef AFMT_S24_PACKED
if (oss_format == AFMT_S24_PACKED)
audio_format->reverse_endian =
G_BYTE_ORDER != G_LITTLE_ENDIAN;
#endif
return true;
case ERROR:

@@ -214,15 +214,6 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
stream_description.mSampleRate = audio_format->sample_rate;
stream_description.mFormatID = kAudioFormatLinearPCM;
stream_description.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger;
#if G_BYTE_ORDER == G_BIG_ENDIAN
stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif
stream_description.mBytesPerPacket =
audio_format_frame_size(audio_format);
stream_description.mFramesPerPacket = 1;
stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
stream_description.mChannelsPerFrame = audio_format->channels;
switch (audio_format->format) {
case SAMPLE_FORMAT_S8:
@@ -239,6 +230,16 @@ osx_output_open(void *data, struct audio_format *audio_format, GError **error)
break;
}
#if G_BYTE_ORDER == G_BIG_ENDIAN
stream_description.mFormatFlags |= kLinearPCMFormatFlagIsBigEndian;
#endif
stream_description.mBytesPerPacket =
audio_format_frame_size(audio_format);
stream_description.mFramesPerPacket = 1;
stream_description.mBytesPerFrame = stream_description.mBytesPerPacket;
stream_description.mChannelsPerFrame = audio_format->channels;
result = AudioUnitSetProperty(od->au, kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input, 0,
&stream_description,

@@ -494,7 +494,7 @@ shout_tag_to_metadata(const struct tag *tag, char *dest, size_t size)
}
}
snprintf(dest, size, "%s - %s", title, artist);
snprintf(dest, size, "%s - %s", artist, title);
}
static void my_shout_set_tag(void *data,

@@ -93,7 +93,7 @@ solaris_output_open(void *data, struct audio_format *audio_format,
/* open the device in non-blocking mode */
so->fd = open_cloexec(so->device, O_WRONLY|O_NONBLOCK);
so->fd = open_cloexec(so->device, O_WRONLY|O_NONBLOCK, 0);
if (so->fd < 0) {
g_set_error(error, solaris_output_quark(), errno,
"Failed to open %s: %s",

@@ -115,6 +115,7 @@ audio_output_open(struct audio_output *ao,
{
bool open;
assert(audio_format_valid(audio_format));
assert(mp != NULL);
if (ao->fail_timer != NULL) {

@@ -95,6 +95,8 @@ ao_filter_open(struct audio_output *ao,
struct audio_format *audio_format,
GError **error_r)
{
assert(audio_format_valid(audio_format));
/* the replay_gain filter cannot fail here */
if (ao->replay_gain_filter != NULL)
filter_open(ao->replay_gain_filter, audio_format, error_r);
@@ -136,6 +138,7 @@ ao_open(struct audio_output *ao)
assert(!ao->open);
assert(ao->pipe != NULL);
assert(ao->chunk == NULL);
assert(audio_format_valid(&ao->in_audio_format));
if (ao->fail_timer != NULL) {
/* this can only happen when this
@@ -164,6 +167,8 @@ ao_open(struct audio_output *ao)
return;
}
assert(audio_format_valid(filter_audio_format));
ao->out_audio_format = *filter_audio_format;
audio_format_mask_apply(&ao->out_audio_format,
&ao->config_audio_format);
@@ -303,7 +308,7 @@ ao_wait(struct audio_output *ao)
GTimeVal tv;
g_get_current_time(&tv);
g_time_val_add(&tv, delay * 1000);
g_cond_timed_wait(ao->cond, ao->mutex, &tv);
(void)g_cond_timed_wait(ao->cond, ao->mutex, &tv);
if (ao->command != AO_COMMAND_NONE)
return false;
@@ -463,12 +468,9 @@ ao_play_chunk(struct audio_output *ao, const struct music_chunk *chunk)
/* don't automatically reopen this device for
10 seconds */
g_mutex_lock(ao->mutex);
assert(ao->fail_timer == NULL);
ao->fail_timer = g_timer_new();
g_mutex_unlock(ao->mutex);
return false;
}

@@ -49,7 +49,7 @@ const int16_t *pcm_byteswap_16(struct pcm_buffer *buffer,
static inline uint32_t swab32(uint32_t x)
{
return (x << 24) |
return (x << 24) |
((x & 0xff00) << 8) |
((x & 0xff0000) >> 8) |
(x >> 24);

@@ -20,9 +20,9 @@
#ifndef MPD_PIPE_H
#define MPD_PIPE_H
#ifndef NDEBUG
#include <stdbool.h>
#ifndef NDEBUG
struct audio_format;
#endif

@@ -356,16 +356,9 @@ player_check_decoder_startup(struct player *player)
static bool
player_send_silence(struct player *player)
{
struct music_chunk *chunk;
size_t frame_size =
audio_format_frame_size(&player->play_audio_format);
/* this formula ensures that we don't send
partial frames */
unsigned num_frames = sizeof(chunk->data) / frame_size;
assert(audio_format_defined(&player->play_audio_format));
chunk = music_buffer_allocate(player_buffer);
struct music_chunk *chunk = music_buffer_allocate(player_buffer);
if (chunk == NULL) {
g_warning("Failed to allocate silence buffer");
return false;
@@ -375,6 +368,12 @@ player_send_silence(struct player *player)
chunk->audio_format = player->play_audio_format;
#endif
size_t frame_size =
audio_format_frame_size(&player->play_audio_format);
/* this formula ensures that we don't send
partial frames */
unsigned num_frames = sizeof(chunk->data) / frame_size;
chunk->times = -1.0; /* undefined time stamp */
chunk->length = num_frames * frame_size;
memset(chunk->data, 0, chunk->length);
@@ -396,8 +395,6 @@ static bool player_seek_decoder(struct player *player)
{
struct song *song = pc.next_song;
struct decoder_control *dc = player->dc;
double where;
bool ret;
assert(pc.next_song != NULL);
@@ -413,8 +410,7 @@ static bool player_seek_decoder(struct player *player)
/* re-start the decoder */
player_dc_start(player, player->pipe);
ret = player_wait_for_decoder(player);
if (!ret) {
if (!player_wait_for_decoder(player)) {
/* decoder failure */
player_command_finished();
return false;
@@ -435,8 +431,7 @@ static bool player_seek_decoder(struct player *player)
/* wait for the decoder to complete initialization */
while (player->decoder_starting) {
ret = player_check_decoder_startup(player);
if (!ret) {
if (!player_check_decoder_startup(player)) {
/* decoder failure */
player_command_finished();
return false;
@@ -445,14 +440,13 @@ static bool player_seek_decoder(struct player *player)
/* send the SEEK command */
where = pc.seek_where;
double where = pc.seek_where;
if (where > pc.total_time)
where = pc.total_time - 0.1;
if (where < 0.0)
where = 0.0;
ret = dc_seek(dc, where + song->start_ms / 1000.0);
if (!ret) {
if (!dc_seek(dc, where + song->start_ms / 1000.0)) {
/* decoder failure */
player_command_finished();
return false;
@@ -583,14 +577,12 @@ static void player_process_command(struct player *player)
static void
update_song_tag(struct song *song, const struct tag *new_tag)
{
struct tag *old_tag;
if (song_is_file(song))
/* don't update tags of local files, only remote
streams may change tags dynamically */
return;
old_tag = song->tag;
struct tag *old_tag = song->tag;
song->tag = tag_dup(new_tag);
if (old_tag != NULL)
@@ -648,15 +640,14 @@ static bool
play_next_chunk(struct player *player)
{
struct decoder_control *dc = player->dc;
struct music_chunk *chunk = NULL;
unsigned cross_fade_position;
bool success;
if (!audio_output_all_wait(64))
/* the output pipe is still large enough, don't send
another chunk */
return true;
unsigned cross_fade_position;
struct music_chunk *chunk = NULL;
if (player->xfade == XFADE_ENABLED &&
player_dc_at_next_song(player) &&
(cross_fade_position = music_pipe_size(player->pipe))
@@ -694,6 +685,19 @@ play_next_chunk(struct player *player)
chunk->mix_ratio = nan("");
}
if (music_chunk_is_empty(other_chunk)) {
/* the "other" chunk was a music_chunk
which had only a tag, but no music
data - we cannot cross-fade that;
but since this happens only at the
beginning of the new song, we can
easily recover by throwing it away
now */
music_buffer_return(player_buffer,
other_chunk);
other_chunk = NULL;
}
chunk->other = other_chunk;
} else {
/* there are not enough decoded chunks yet */
@@ -732,9 +736,7 @@ play_next_chunk(struct player *player)
/* play the current chunk */
success = play_chunk(player->song, chunk, &player->play_audio_format);
if (!success) {
if (!play_chunk(player->song, chunk, &player->play_audio_format)) {
music_buffer_return(player_buffer, chunk);
player_lock();
@@ -776,11 +778,9 @@ play_next_chunk(struct player *player)
static bool
player_song_border(struct player *player)
{
char *uri;
player->xfade = XFADE_UNKNOWN;
uri = song_get_uri(player->song);
char *uri = song_get_uri(player->song);
g_message("played \"%s\"", uri);
g_free(uri);
@@ -875,16 +875,17 @@ static void do_play(struct decoder_control *dc)
if (player.decoder_starting) {
/* wait until the decoder is initialized completely */
bool success;
const struct song *song;
success = player_check_decoder_startup(&player);
if (!success)
if (!player_check_decoder_startup(&player))
break;
/* seek to the beginning of the range */
song = decoder_current_song(dc);
const struct song *song = decoder_current_song(dc);
if (song != NULL && song->start_ms > 0 &&
/* we must not send a seek command until
the decoder is initialized
completely */
!player.decoder_starting &&
!dc_seek(dc, song->start_ms / 1000.0))
player_dc_stop(&player);
@@ -1092,10 +1093,9 @@ static gpointer player_task(G_GNUC_UNUSED gpointer arg)
void player_create(void)
{
GError *e = NULL;
assert(pc.thread == NULL);
GError *e = NULL;
pc.thread = g_thread_create(player_task, NULL, true, &e);
if (pc.thread == NULL)
MPD_ERROR("Failed to spawn player task: %s", e->message);

@@ -72,6 +72,14 @@ apply_song_metadata(struct song *dest, const struct song *src)
song_free(dest);
}
if (dest->tag != NULL && dest->tag->time > 0 &&
src->start_ms > 0 && src->end_ms == 0 &&
src->start_ms / 1000 < (unsigned)dest->tag->time)
/* the range is open-ended, and the playlist plugin
did not know the total length of the song file
(e.g. last track on a CUE file); fix it up here */
tmp->tag->time = dest->tag->time - src->start_ms / 1000;
return tmp;
}
@@ -97,6 +105,13 @@ playlist_check_translate_song(struct song *song, const char *base_uri)
}
}
if (base_uri != NULL && strcmp(base_uri, ".") == 0)
/* g_path_get_dirname() returns "." when there is no
directory name in the given path; clear that now,
because it would break the database lookup
functions */
base_uri = NULL;
if (g_path_is_absolute(uri)) {
/* XXX fs_charset vs utf8? */
char *prefix = base_uri != NULL
@@ -121,7 +136,7 @@ playlist_check_translate_song(struct song *song, const char *base_uri)
else
uri = g_strdup(uri);
if (uri_has_scheme(base_uri)) {
if (uri_has_scheme(uri)) {
dest = song_remote_new(uri);
g_free(uri);
} else {

@@ -51,6 +51,12 @@ playlist_vector_init(struct playlist_vector *pv)
void
playlist_vector_deinit(struct playlist_vector *pv);
static inline bool
playlist_vector_is_empty(const struct playlist_vector *pv)
{
return pv->head == NULL;
}
struct playlist_metadata *
playlist_vector_find(struct playlist_vector *pv, const char *name);

@@ -47,7 +47,7 @@ poison_noaccess(void *p, size_t length)
memset(p, 0x01, length);
#ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_MAKE_MEM_NOACCESS(p, length);
(void)VALGRIND_MAKE_MEM_NOACCESS(p, length);
#endif
#endif
}
@@ -68,7 +68,7 @@ poison_undefined(void *p, size_t length)
memset(p, 0x02, length);
#ifdef HAVE_VALGRIND_MEMCHECK_H
VALGRIND_MAKE_MEM_UNDEFINED(p, length);
(void)VALGRIND_MAKE_MEM_UNDEFINED(p, length);
#endif
#endif
}

78
src/replay_gain_ape.c Normal file

@@ -0,0 +1,78 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include "replay_gain_ape.h"
#include "replay_gain_info.h"
#include "ape.h"
#include <glib.h>
#include <string.h>
#include <stdlib.h>
struct rg_ape_ctx {
struct replay_gain_info *info;
bool found;
};
static bool
replay_gain_ape_callback(unsigned long flags, const char *key,
const char *_value, size_t value_length, void *_ctx)
{
struct rg_ape_ctx *ctx = _ctx;
/* we only care about utf-8 text tags */
if ((flags & (0x3 << 1)) != 0)
return true;
char value[16];
if (value_length >= sizeof(value))
return true;
memcpy(value, _value, value_length);
value[value_length] = 0;
if (g_ascii_strcasecmp(key, "replaygain_track_gain") == 0) {
ctx->info->tuples[REPLAY_GAIN_TRACK].gain = atof(value);
ctx->found = true;
} else if (g_ascii_strcasecmp(key, "replaygain_album_gain") == 0) {
ctx->info->tuples[REPLAY_GAIN_ALBUM].gain = atof(value);
ctx->found = true;
} else if (g_ascii_strcasecmp(key, "replaygain_track_peak") == 0) {
ctx->info->tuples[REPLAY_GAIN_TRACK].peak = atof(value);
ctx->found = true;
} else if (g_ascii_strcasecmp(key, "replaygain_album_peak") == 0) {
ctx->info->tuples[REPLAY_GAIN_ALBUM].peak = atof(value);
ctx->found = true;
}
return true;
}
bool
replay_gain_ape_read(const char *path_fs, struct replay_gain_info *info)
{
struct rg_ape_ctx ctx = {
.info = info,
.found = false,
};
return tag_ape_scan(path_fs, replay_gain_ape_callback, &ctx) &&
ctx.found;
}

32
src/replay_gain_ape.h Normal file

@@ -0,0 +1,32 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* 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.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_REPLAY_GAIN_APE_H
#define MPD_REPLAY_GAIN_APE_H
#include "check.h"
#include <stdbool.h>
struct replay_gain_info;
bool
replay_gain_ape_read(const char *path_fs, struct replay_gain_info *info);
#endif

@@ -21,11 +21,7 @@
#include "tag_ape.h"
#include "tag.h"
#include "tag_table.h"
#include <glib.h>
#include <assert.h>
#include <stdio.h>
#include "ape.h"
static const char *const ape_tag_names[TAG_NUM_OF_ITEM_TYPES] = {
[TAG_ALBUM_ARTIST] = "album artist",
@@ -56,101 +52,45 @@ tag_ape_import_item(struct tag *tag, unsigned long flags,
if (tag == NULL)
tag = tag_new();
tag_add_item_n(tag, type, value, value_length);
const char *end = value + value_length;
while (true) {
/* multiple values are separated by null bytes */
const char *n = memchr(value, 0, end - value);
if (n != NULL) {
if (n > value)
tag_add_item_n(tag, type, value, n - value);
value = n + 1;
} else {
if (end > value)
tag_add_item_n(tag, type, value, end - value);
break;
}
}
return tag;
}
struct tag_ape_ctx {
struct tag *tag;
};
static bool
tag_ape_callback(unsigned long flags, const char *key,
const char *value, size_t value_length, void *_ctx)
{
struct tag_ape_ctx *ctx = _ctx;
ctx->tag = tag_ape_import_item(ctx->tag, flags, key,
value, value_length);
return true;
}
struct tag *
tag_ape_load(const char *file)
{
struct tag *ret = NULL;
FILE *fp;
int tagCount;
char *buffer = NULL;
char *p;
size_t tagLen;
size_t size;
unsigned long flags;
char *key;
struct tag_ape_ctx ctx = { .tag = NULL };
struct {
unsigned char id[8];
uint32_t version;
uint32_t length;
uint32_t tagCount;
unsigned char flags[4];
unsigned char reserved[8];
} footer;
fp = fopen(file, "rb");
if (!fp)
return NULL;
/* determine if file has an apeV2 tag */
if (fseek(fp, 0, SEEK_END))
goto fail;
size = (size_t)ftell(fp);
if (fseek(fp, size - sizeof(footer), SEEK_SET))
goto fail;
if (fread(&footer, 1, sizeof(footer), fp) != sizeof(footer))
goto fail;
if (memcmp(footer.id, "APETAGEX", sizeof(footer.id)) != 0)
goto fail;
if (GUINT32_FROM_LE(footer.version) != 2000)
goto fail;
/* find beginning of ape tag */
tagLen = GUINT32_FROM_LE(footer.length);
if (tagLen <= sizeof(footer) + 10)
goto fail;
if (tagLen > 1024 * 1024)
/* refuse to load more than one megabyte of tag data */
goto fail;
if (fseek(fp, size - tagLen, SEEK_SET))
goto fail;
/* read tag into buffer */
tagLen -= sizeof(footer);
assert(tagLen > 10);
buffer = g_malloc(tagLen);
if (fread(buffer, 1, tagLen, fp) != tagLen)
goto fail;
/* read tags */
tagCount = GUINT32_FROM_LE(footer.tagCount);
p = buffer;
while (tagCount-- && tagLen > 10) {
size = GUINT32_FROM_LE(*(const uint32_t *)p);
p += 4;
tagLen -= 4;
flags = GUINT32_FROM_LE(*(const uint32_t *)p);
p += 4;
tagLen -= 4;
/* get the key */
key = p;
while (tagLen > size && *p != '\0') {
p++;
tagLen--;
}
p++;
tagLen--;
/* get the value */
if (tagLen < size)
goto fail;
ret = tag_ape_import_item(ret, flags, key, p, size);
p += size;
tagLen -= size;
}
fail:
if (fp)
fclose(fp);
g_free(buffer);
return ret;
tag_ape_scan(file, tag_ape_callback, &ctx);
return ctx.tag;
}

@@ -126,17 +126,16 @@ import_id3_string(bool is_id3v1, const id3_ucs4_t *ucs4)
* - string list
*/
static void
tag_id3_import_text(struct tag *dest, struct id3_tag *tag, const char *id,
enum tag_type type)
tag_id3_import_text_frame(struct tag *dest, struct id3_tag *tag,
const struct id3_frame *frame,
enum tag_type type)
{
struct id3_frame const *frame;
id3_ucs4_t const *ucs4;
id3_utf8_t *utf8;
union id3_field const *field;
unsigned int nstrings, i;
frame = id3_tag_findframe(tag, id, 0);
if (frame == NULL || frame->nfields != 2)
if (frame->nfields != 2)
return;
/* check the encoding field */
@@ -170,6 +169,20 @@ tag_id3_import_text(struct tag *dest, struct id3_tag *tag, const char *id,
}
}
/**
* Import all text frames with the specified id (ID3v2.4.0 section
* 4.2). This is a wrapper for tag_id3_import_text_frame().
*/
static void
tag_id3_import_text(struct tag *dest, struct id3_tag *tag, const char *id,
enum tag_type type)
{
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != NULL; ++i)
tag_id3_import_text_frame(dest, tag, frame, type);
}
/**
* Import a "Comment frame" (ID3v2.4.0 section 4.10). It
* contains 4 fields:
@@ -180,16 +193,15 @@ tag_id3_import_text(struct tag *dest, struct id3_tag *tag, const char *id,
* - full string (we use this one)
*/
static void
tag_id3_import_comment(struct tag *dest, struct id3_tag *tag, const char *id,
enum tag_type type)
tag_id3_import_comment_frame(struct tag *dest, struct id3_tag *tag,
const struct id3_frame *frame,
enum tag_type type)
{
struct id3_frame const *frame;
id3_ucs4_t const *ucs4;
id3_utf8_t *utf8;
union id3_field const *field;
frame = id3_tag_findframe(tag, id, 0);
if (frame == NULL || frame->nfields != 4)
if (frame->nfields != 4)
return;
/* for now I only read the 4th field, with the fullstring */
@@ -209,6 +221,20 @@ tag_id3_import_comment(struct tag *dest, struct id3_tag *tag, const char *id,
g_free(utf8);
}
/**
* Import all comment frames (ID3v2.4.0 section 4.10). This is a
* wrapper for tag_id3_import_comment_frame().
*/
static void
tag_id3_import_comment(struct tag *dest, struct id3_tag *tag, const char *id,
enum tag_type type)
{
const struct id3_frame *frame;
for (unsigned i = 0;
(frame = id3_tag_findframe(tag, id, i)) != NULL; ++i)
tag_id3_import_comment_frame(dest, tag, frame, type);
}
/**
* Parse a TXXX name, and convert it to a tag_type enum value.
* Returns TAG_NUM_OF_ITEM_TYPES if the TXXX name is not understood.

@@ -74,7 +74,7 @@ void timer_add(Timer *timer, int size)
unsigned
timer_delay(const Timer *timer)
{
int64_t delay = (timer->time - now()) / 1000;
int64_t delay = (int64_t)(timer->time - now()) / 1000;
if (delay < 0)
return 0;

@@ -300,6 +300,9 @@ stat_directory(const struct directory *directory, struct stat *st)
if (path_fs == NULL)
return -1;
ret = stat(path_fs, st);
if (ret < 0)
g_warning("Failed to stat %s: %s", path_fs, g_strerror(errno));
g_free(path_fs);
return ret;
}
@@ -316,6 +319,9 @@ stat_directory_child(const struct directory *parent, const char *name,
return -1;
ret = stat(path_fs, st);
if (ret < 0)
g_warning("Failed to stat %s: %s", path_fs, g_strerror(errno));
g_free(path_fs);
return ret;
}
@@ -546,6 +552,32 @@ update_container_file( struct directory* directory,
return true;
}
/**
* Checks if the given permissions on the mapped file are given.
*/
static bool
directory_child_access(const struct directory *directory,
const char *name, int mode)
{
#ifdef WIN32
/* access() is useless on WIN32 */
(void)directory;
(void)name;
(void)mode;
return true;
#else
char *path = map_directory_child_fs(directory, name);
if (path == NULL)
/* something went wrong, but that isn't a permission
problem */
return true;
bool success = access(path, mode) == 0 || errno != EACCES;
g_free(path);
return success;
#endif
}
static void
update_regular_file(struct directory *directory,
const char *name, const struct stat *st)
@@ -562,6 +594,14 @@ update_regular_file(struct directory *directory,
{
struct song* song = songvec_find(&directory->songs, name);
if (!directory_child_access(directory, name, R_OK)) {
g_warning("no read permissions on %s/%s",
directory_get_path(directory), name);
if (song != NULL)
delete_song(directory, song);
return;
}
if (!(song != NULL && st->st_mtime == song->mtime &&
!walk_discard) &&
plugin->container_scan != NULL)