Compare commits

...

893 Commits

Author SHA1 Message Date
Avuton Olrich
76e3dec723 mpd version 0.17.2 2012-09-30 03:27:38 -07:00
Max Kellermann
ba6ef53ef9 decoder_control: remove MixRamp debug messages
These are confusing, and since MixRamp development has ceased, not
useful to anybody.
2012-09-25 11:08:16 +02:00
Max Kellermann
c93a28c641 configure.ac: don't auto-detect the Vorbis encoder when Tremor is enabled
libvorbisidec and libvorbis export the same symbols, which is a
dangerous thing.  Since libvorbisenc depends on libvorbis, this can
get nasty, so let's disable the Vorbis encoder unless the user
explicitly wants it.
2012-09-25 10:41:39 +02:00
Max Kellermann
7088a679a2 decoder/wavpack: support all APEv2 tags
WavPack tags are always APEv2, by definition.  Reuse the tag_table
from tag_ape.c, instead of rolling our own.
2012-09-25 09:37:16 +02:00
Max Kellermann
04c02a1eb8 locate: cast enum tag_type to int before comparing with integer
Avoids clang pickiness.  This code is not correct, but we'll fix that
another day.
2012-09-22 09:48:27 +02:00
Max Kellermann
41487426f5 decoder/_ogg_common: fix buffer size check
Fixes potential access to uninitialised memory.
2012-09-04 11:22:15 +02:00
Max Kellermann
0d24250aa7 decoder/_ogg_common: simplify the large "if" expression 2012-09-04 11:22:05 +02:00
Wieland Hoffmann
2050e2f886 mpd.conf(5): Use the correct default value for max_playlist_length 2012-09-03 22:49:51 +02:00
Max Kellermann
013e8479af AudioCompress: abort on out-of-memory
This library crashes on out-of-memory (NULL pointer dereference).
There's not much useful MPD can do in such a situation, so let's
explicitly abort instead, just like GLib does.
2012-09-03 22:45:33 +02:00
Max Kellermann
27535a7f78 update_walk: fix unsafe readlink() usage 2012-09-03 22:41:04 +02:00
Max Kellermann
acaa725478 playlist/cue: map "PERFORMER" to "artist" or "album artist"
Implements Mantis ticket 0003549.
2012-08-25 09:56:14 +02:00
Max Kellermann
f351550534 player_thread: disable cross-fading in "single" mode
This commit reimplements the core of the "single" mode.  Instead of
doing the detection in the playlist code from the outside, it is moved
to the player thread, which gets a new option called "border_pause".
It will now pause playback exactly at the beginning of the new song,
making the feature more reliable.

Now that the player thread knows what will happen, it can suppress
cross-fading.

Fixes mantis tickets 0003055 and 0003166.
2012-08-25 09:38:41 +02:00
Max Kellermann
66ecf39efe command: make "single" a bool 2012-08-21 19:38:08 +02:00
Max Kellermann
5ad21d7e98 queue_save: save song priorities 2012-08-21 19:17:14 +02:00
Max Kellermann
ef5125f8f4 playlist_print: fix memory leak 2012-08-16 00:01:01 +02:00
Max Kellermann
bf2e07074b playlist_song: pass const song to _check_load_song() 2012-08-16 00:00:50 +02:00
Max Kellermann
20695ef369 playlist_song: fix user-after-free bug 2012-08-16 00:00:21 +02:00
Max Kellermann
9374e0f445 player_thread: add local variable "start_ms"
Just in case "song" becomes invalid at some point.
2012-08-15 22:51:48 +02:00
Max Kellermann
19ed233118 playlist: fix unprotected player_control access 2012-08-15 22:47:08 +02:00
Max Kellermann
faa4fff4dd filter/volume: include cleanup 2012-08-15 22:45:03 +02:00
Max Kellermann
2276e7677b mapper: fix potential crash in file permission check 2012-08-15 22:44:13 +02:00
Max Kellermann
93f9c2ab6b doc/user: add wildmidi documentation 2012-08-15 01:03:16 +02:00
Max Kellermann
4a993cd79e decoder/fluidsynth: add "sample_rate" setting 2012-08-15 00:57:32 +02:00
Max Kellermann
02325d2ede decoder/fluidsynth: add "soundfont" setting
Replaces the old global "soundfont" which never worked.
2012-08-15 00:51:45 +02:00
Max Kellermann
9c83464b95 configure.ac: auto-detect libfluidsynth
Now that the libfluidsynth API was sanitized, we can enable the plugin
automatically if libfluidsynth is installed.
2012-08-15 00:48:52 +02:00
Max Kellermann
b1bbd70f0f decoder/fluidsynth: stop playback at end of file
Use libfluidsynth's new function fluid_player_get_status().
2012-08-15 00:47:10 +02:00
Max Kellermann
c31d11bfe0 decoder/fluidsynth: don't duplicate path
The libfluidsynth now accepts const strings.
2012-08-15 00:39:22 +02:00
Max Kellermann
c8ec85d649 decoder/fluidsynth: check if file is really a MIDI
Use fluid_is_midifile() to verify the file format.
2012-08-15 00:36:04 +02:00
Max Kellermann
e291f3d257 decoder/fluidsynth: remove throttle (requires libfluidsynth 1.1)
The libfluidsynth API is now sane, and does not require real-time
decoding.
2012-08-15 00:29:38 +02:00
Max Kellermann
dc22846d58 log: store duplicated path string
Don't free the string right after calling log_init_file().  Add a new
function log_deinit() that frees the string on shutdown.

This fixes cycling the log file after SIGHUP (Mantis ticket 0003524).
2012-08-14 23:16:46 +02:00
Max Kellermann
c9aaabb5d4 output/jack: implement method delay()
Eliminate the g_usleep() call.
2012-08-14 22:47:25 +02:00
Max Kellermann
335d5d5d72 output/pulse: implement method delay()
Reduce command latency while paused.
2012-08-14 22:30:46 +02:00
Max Kellermann
51d793bec1 output/pulse: simplify _wait_stream()
One large loop and only one pa_stream_get_state() call.
2012-08-14 22:22:55 +02:00
Max Kellermann
249dcd967e output/httpd: move delay from _pause() to _delay() 2012-08-14 21:54:47 +02:00
Max Kellermann
302972e9fc output/httpd: fix throttling bug after resuming playback
Reset the timer when paused and no client is connected.

This fixes Mantis ticket 0003527.
2012-08-14 21:39:33 +02:00
Max Kellermann
31b380b266 output/httpd: move code to _has_clients() 2012-08-14 20:22:32 +02:00
Max Kellermann
a869dfea85 timer: use monotonic clock if available 2012-08-14 19:07:31 +02:00
Max Kellermann
12838c6294 input/ffmpeg: remove fallback AV_VERSION_INT definition
This is part of libavutil.
2012-08-14 19:07:27 +02:00
Wieland Hoffmann
49c7102547 mpd.conf(5): Document the existence of musicbrainz_ tags
Additionally, update mpdconf.example to refer to mpd.conf(5) for the
complete list of tags instead of trying to repeat it.
2012-08-14 09:43:18 +02:00
Max Kellermann
1ae8972859 mapper: fix non-UTF8 music directory name
Duplicate the music_dir variable: one encoded in UTF-8, and another
one using the configured filesystem character set.  This fixes an
ancient MPD bug.
2012-08-14 02:28:04 +02:00
Max Kellermann
adcd2c8eac playlist_song: use map_to_relative_path() 2012-08-14 02:25:19 +02:00
Max Kellermann
45ff355835 playlist_song: improve const-correctness 2012-08-14 02:24:16 +02:00
Max Kellermann
f8bf3afeae playlist_song: move code to playlist_check_load_song() 2012-08-14 02:17:25 +02:00
Max Kellermann
f703da1516 valgrind.suppressions: suppressions for GStaticMutex and more 2012-08-14 01:58:17 +02:00
Max Kellermann
a582deee2c input_stream, main: remove obsolete GLib version checks
MPD requires GLib 2.16.
2012-08-14 01:57:53 +02:00
Anton Khirnov
12be9e818f client_file: remove pure attribute from client_allow_file().
That function is not pure, it writes to error.

When marked as pure, the compiler is allowed to assume it does not do
anything to error, so it can remain NULL, which would result in an
invalid read in print_error().
2012-08-13 07:55:40 +02:00
Avuton Olrich
281cd7c057 Modify version string to post-release version 0.17.2~git 2012-07-31 19:05:52 -07:00
Avuton Olrich
63e8766091 mpd version 0.17.1 2012-07-31 19:05:52 -07:00
Max Kellermann
18da582c87 configure.ac: replace MPD_CHECK_FLAG with autoconf-archive scripts
Use standard scripts instead of MPD's custom implementation.
2012-07-30 11:10:04 +02:00
Max Kellermann
0562cf99ba configure.ac: add -I to CPPFLAGS, not CFLAGS 2012-07-30 11:05:12 +02:00
Max Kellermann
60ac702038 tcp_socket, ...: remove obsolet RAOP sources 2012-07-30 06:57:49 +02:00
Max Kellermann
1dedb96478 tag_ape: return false if no usable tag was found
Ignore APE tags that have no usable tags, and use the ID3 tag instead.
This is useful when the APE tag only contains replay gain, and the
real tags are stored as ID3.  This implements feature request Mantis
.
2012-07-29 18:44:03 +02:00
Max Kellermann
7537722a44 cue_parser: support file types "MP3", "AIFF"
These two strings are common "FILE" types.
2012-07-26 23:01:40 +02:00
Max Kellermann
4ebd69193e Makefile.am: updated web server for "upload" target 2012-07-13 10:19:38 +02:00
Jurgen Kramer
d4d92ac1a7 Add song duration to DSF and DSDIFF DSD decoders. 2012-07-13 10:14:17 +02:00
Max Kellermann
5385d1fa80 aiff: support the AIFC format 2012-07-10 01:53:46 +02:00
Max Kellermann
dbee2f1996 output_init: put the "convert" filter at the end of the list
No, really!  This fixes a regression of commit 74617389, which
changed the order of filter plugins.
2012-07-10 01:30:22 +02:00
Max Kellermann
6dd70926fa test/test_pcm: add pcm_volume tests 2012-07-10 01:30:02 +02:00
Max Kellermann
5dfc0918c3 require GLib 2.16
GLib 2.16 was released more than 4 years ago.  Let's remove some cruft
from the glib_compat.h header, and avoid new cruft to it.
2012-07-10 01:28:52 +02:00
Max Kellermann
2eb14658d3 Merge branch 'fix-typo' of https://github.com/sol/mpd 2012-07-10 00:32:09 +02:00
Jonathan Neuschäfer
c1f196dbec command: require appropriate permissions for searchadd{,pl} 2012-07-10 00:23:19 +02:00
Max Kellermann
ce108acebb configure.ac: increment version number to 0.17.1 2012-07-09 22:50:32 +02:00
Simon Hengel
0555e2c781 Fix typo 2012-07-08 09:19:12 +02:00
Max Kellermann
6bfd1f1727 mpd version 0.17 2012-06-27 11:38:13 +02:00
Max Kellermann
baa77c8ae3 Makefile.am: distribute src/output/*.h 2012-06-27 10:11:21 +02:00
Jurgen Kramer
7235dbadfd patch to split DSD decoder into separate decoders for DSF en DFF. Move common
functions to new dsdlib. Update user doc.
2012-06-27 09:54:24 +02:00
geneticdrift
ecec41025f Documentation for commands searchadd, searchaddpl, and for tcp keepalive config options 2012-06-27 09:50:35 +02:00
geneticdrift
799843cc97 New command searchaddpl
Search and add search result to a stored playlist.
2012-06-27 09:49:17 +02:00
geneticdrift
16e91baa79 New command searchadd similar to command findadd. 2012-06-27 09:41:15 +02:00
Max Kellermann
f2536445f7 locate: make variables more local 2012-06-27 09:36:02 +02:00
Max Kellermann
ede70ee3a4 update_walk: move code to update_song.c 2012-06-13 22:14:16 +02:00
Max Kellermann
66ed427a57 update_walk: move code to update_container.c 2012-06-13 22:11:43 +02:00
Max Kellermann
c9e63e9fdb update_walk: move code to update_archive.c 2012-06-13 21:52:46 +02:00
Max Kellermann
ddf7f5c131 update_internal.h: split header 2012-06-13 21:38:28 +02:00
Max Kellermann
660e40d07e update_walk: split update_regular_file() 2012-06-13 21:33:23 +02:00
Max Kellermann
9f3db5a70b directory: require db lock for _{add,remove}_song() 2012-06-13 21:26:32 +02:00
Max Kellermann
1a59730782 update_walk: add "pure" attributes 2012-06-13 21:22:41 +02:00
Max Kellermann
20029e7ce8 update_walk: move code to make_directory_if_modified() 2012-06-13 21:22:00 +02:00
Max Kellermann
fcb7950811 update_walk: fix coding style 2012-06-13 20:48:30 +02:00
Max Kellermann
4eb57e1e9a Merge branch 'v0.16.x'
Conflicts:
	src/cmdline.c
	src/decoder/wildmidi_decoder_plugin.c
	src/gcc.h
	src/glib_compat.h
	src/input_stream.c
	src/output_list.c
	src/output_thread.c
	valgrind.suppressions
2012-06-12 23:22:03 +02:00
Max Kellermann
1d52e2cc77 valgrind.suppressions: GLib 2.32 updates 2012-06-12 22:54:58 +02:00
Max Kellermann
209aceeb14 valgrind.suppressions: merge changes from master 2012-06-12 22:39:54 +02:00
Max Kellermann
ae70875f45 cmdline: consistent plugin listings 2012-06-12 22:29:04 +02:00
Max Kellermann
eda7410f4c cmdline: dump list of input plugins 2012-06-12 22:24:42 +02:00
Max Kellermann
e60141b4dd input_registry: add _for_each() macros 2012-06-12 22:21:48 +02:00
Max Kellermann
5b21742095 cmdline: dump list of playlist plugins 2012-06-12 22:16:13 +02:00
Max Kellermann
5665de5ee7 playlist_list: add _for_each() macros 2012-06-12 22:12:06 +02:00
Max Kellermann
d5b9be0393 cmdline: change --version formatting 2012-06-12 21:15:46 +02:00
Max Kellermann
d2d9b45a81 decoder_list: add _for_each() macros 2012-06-12 21:15:46 +02:00
Max Kellermann
9ebbdb9b0b archive_list: add _for_each() macros 2012-06-12 20:58:43 +02:00
Max Kellermann
48da345e79 cmdline: don't initalise archive plugins for --version
Dump all archive plugins, even those that fail to initialise.
2012-06-12 20:52:04 +02:00
Max Kellermann
edbfa46cbc encoder_list: add macro _for_each() 2012-06-12 20:39:53 +02:00
Max Kellermann
90709a6de4 encoder_list: make the list truly "const" 2012-06-12 20:36:53 +02:00
Max Kellermann
992c2fa2d4 output_list: declare variables inside _plugins_for_each()
Don't require the caller to provide them.
2012-06-12 20:31:32 +02:00
Max Kellermann
ed915fed92 output_list: make the list truly "const" 2012-06-12 20:30:55 +02:00
Max Kellermann
8aa29d5a66 output_list: simplify audio_output_plugins_for_each() call 2012-06-12 20:22:40 +02:00
Max Kellermann
9604e0aad2 cmdline: update copyright year 2012-06-12 19:55:30 +02:00
Denis Krjuchkov
25d053cbf2 Work around incorrect g_file_test() behavior on Win32
g_file_test is redefined to be g_file_test_utf8 and thus can't handle
non-ASCII characters. This fix adds simple wrapper (taken from glib)
that fixes encoding and calls g_file_test_utf8. All required inclusions
of glib_compat.h are added as well.
2012-06-12 19:31:19 +02:00
Max Kellermann
055257a210 audio-parser, output_thread: work around -Wmaybe-uninitialized
False positives in gcc 4.7.
2012-06-12 19:31:19 +02:00
Max Kellermann
50cfb997cc gcc.h: backport GCC_CHECK_VERSION() from v0.17.x 2012-06-12 19:22:20 +02:00
Max Kellermann
d662c4c0cc Merge branch 'v0.16.x'
Conflicts:
	NEWS
2012-05-29 23:46:10 +02:00
Max Kellermann
457d98c860 output/raop: delete the RAOP plugin
This plugin is horrible code, I mean it.  Last year, I tried hard to
fix it, but I figured would take less time to do a full rewrite.
Given that I don't even have any device that supports RAOP, I can't do
that properly.  After 16 months, nobody volunteered for fixing it.
Hereby, I delete it, because having no RAOP plugin is better than
having this mess.  Sorry.
2012-05-29 23:15:41 +02:00
Max Kellermann
6bb166aaaa decoder_api: log the decoder plugin name 2012-05-29 22:52:50 +02:00
Jonathan Neuschäfer
cca9bc5176 decoder/ffmpeg: improve "decoding failed" message
"Frame skipped" might cause the impression that the decoding of a whole
song failed.
2012-05-29 22:46:27 +02:00
Jonathan Neuschäfer
8b6b25220d decoder/ffmpeg: add webm as a supported format 2012-05-29 22:38:40 +02:00
Jurgen Kramer
3c3f1b7ff2 Add support for DSF files to DSDIFF decoder - v4
Version 4 of my patch to add DSF support to the DSDIFF
decoder plugin.

This time I have taken a different approach and created a new
read_metadata function specific for reading DSF files. This saves an
indent (and for me a lot of indent nightmares) and also useful for
splitting the DSF and DFF decoders later on.

There are still a few lines which exceed the 80 character width limit by
a few chars. I was not able to stay within the limit and create (for me)
readable code.

Jurgen
2012-05-02 08:47:02 +02:00
Jonathan Dieter
57d89131e9 tag_rva2: parse multiple ID3 "RVA2" tags 2012-04-23 23:29:56 +02:00
Jonathan Dieter
7c6d1896a4 tag_rva2: support separate album/track replay gain 2012-04-23 23:29:53 +02:00
Max Kellermann
ad83c7f704 tag_rva2: move code to rva2_apply_frame() 2012-04-23 23:28:34 +02:00
Max Kellermann
6b52d040b1 test/read_rva2: new debug program for the RVA2 library 2012-04-23 23:00:41 +02:00
Max Kellermann
404fa89937 tag_id3: export tag_id3_load() 2012-04-23 22:51:45 +02:00
Max Kellermann
89377556cd output/alsa: multiply writei() result with out_frame_size
.. and not in_frame_size, because this relates to the frame size being
sent to ALSA.  pcm_export_source_size() will then turn it back into
the in_frame_size scale.
2012-04-23 21:54:09 +02:00
Max Kellermann
ec93114347 pcm_export: consider the pack24 flag in _source_size() 2012-04-23 21:54:09 +02:00
Max Kellermann
df1c5ce314 pcm_export: add _frame_size()
Move code from the ALSA output plugin.
2012-04-23 21:54:09 +02:00
Max Kellermann
a0e4b6e266 output/alsa: fix out_frame_size formula, multiply with channels
The hard-coded "3 bytes" was wrong because it ignored the number of
channels.
2012-04-23 21:54:08 +02:00
Max Kellermann
0de39b64cb configure.ac: work around syntax error
.. when HAVE_WINDOWS was not set.
2012-04-23 21:54:08 +02:00
Max Kellermann
36a7b4e275 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2012-04-06 15:42:41 +02:00
Avuton Olrich
d3cc8e0ac0 Modify version string to post-release version 0.16.9~git 2012-04-04 18:37:47 -07:00
Avuton Olrich
db1ce4eeeb mpd version 0.16.8 2012-04-04 18:37:47 -07:00
Max Kellermann
c22cbbf828 Merge branch 'v0.16.x'
Conflicts:
	src/output/osx_plugin.c
	src/text_input_stream.c
2012-04-05 00:45:39 +02:00
Max Kellermann
5acee73fc8 encoder/vorbis: generate end-of-stream packet when playback ends
Add the encoder_plugin method end().  This is important for the
recorder plugin.
2012-04-05 00:21:53 +02:00
Max Kellermann
466c337bcb encoder_plugin: add state assertions 2012-04-05 00:05:21 +02:00
Max Kellermann
98a468a101 encoder/vorbis: generate end-of-stream packet before tag
Don't reset the ogg_stream_state object, because this discards the
end-of-stream packet that was just added.
2012-04-04 23:59:06 +02:00
Max Kellermann
47c58c01d1 test/test_vorbis_encoder: program to debug the vorbis encoder 2012-04-04 23:58:00 +02:00
Max Kellermann
a9edf85a69 output/jack: check for connection failure before starting playback 2012-04-04 21:40:56 +02:00
Max Kellermann
e7a1862517 output/jack: workaround for libjack1 crash bug 2012-04-04 21:38:29 +02:00
Jurgen Kramer
f930f37d35 Add support for DSD-over-USB version 1.0, remove pre-v1 support 2012-04-04 20:13:15 +02:00
Max Kellermann
4feb57e895 db_lock, archive/bz2, ...: workaround for G_STATIC_MUTEX_INIT warning 2012-04-04 20:13:15 +02:00
Max Kellermann
712e3eb120 input/curl: use g_source_get_time()
g_source_get_current_time() is deprecated since GLib 2.28.  This patch
adds a compatibility wrapper for older GLib versions to glib_compat.h.
2012-04-04 20:05:48 +02:00
Max Kellermann
d8e423df1a directory: use strrchr() instead of g_basename()
g_basename() is deprecated in GLib 2.32.
2012-04-04 19:08:05 +02:00
Max Kellermann
09aa0dc676 uri: remove g_basename() call from uri_get_suffix()
g_basename() is deprecated in GLib 2.32.  Instead, verify that the
suffix does not have a backslash, to catch Windows path names.
2012-04-04 12:22:16 +02:00
Anton Khirnov
83174de420 update: properly skip symlinks in path that is to be updated. 2012-04-04 08:56:45 +02:00
Max Kellermann
8ff0197a43 output/osx: use the fifo_buffer library instead of rolling own
The existing buffer implementation has a major flaw: it is unable to
re-fill the buffer until it has been consumed completely, leading to
many occasions where the render callback needs to generate silence,
just because the play() implementation was unable to append more
data.  The fifo_buffer library handles that well.
2012-03-28 21:51:17 +02:00
Max Kellermann
a2b5db0003 audio_format: remove SAMPLE_FORMAT_DSD_OVER_USB
DSD-over-USB should not be a MPD core format, because it is not a
"natural" format; it is just a temnporary over-the-wire format.  This
format has been implemented in pcm_export, and does not need to be
supported by pcm_convert.
2012-03-27 01:22:50 +02:00
Max Kellermann
2803ec2e96 output/alsa: support 32 bit DSD-over-USB 2012-03-27 01:22:50 +02:00
Max Kellermann
ddd4f675a2 pcm_export: implement 24 to 32 bit conversion
For 32 bit DSD-over-USB support.
2012-03-27 01:22:50 +02:00
Max Kellermann
d271dd2cce output/alsa: use pcm_export for the DSD-over-USB conversion 2012-03-27 01:22:50 +02:00
Max Kellermann
ebfdd37451 pcm_export: support DSD to DSD-over-USB conversion
Prepare for removing SAMPLE_FORMAT_DSD_OVER_USB.
2012-03-27 01:17:11 +02:00
Max Kellermann
f6d6110aaa output/alsa: move pcm_export_open() to caller
Give the caller more control, prepare for DSD-over-USB improvements.
2012-03-27 01:17:11 +02:00
Max Kellermann
a0730cf264 pcm_export: support packing SAMPLE_FORMAT_DSD_OVER_USB
It's a padded 24 bit format.
2012-03-27 00:37:14 +02:00
Max Kellermann
ec61b3a5fc pcm_export: initialize the "pack" buffer 2012-03-27 00:14:37 +02:00
Max Kellermann
521f2294cb pcm_export: fix API documentation 2012-03-27 00:14:37 +02:00
Max Kellermann
2f0674807c output/alsa: more debug output 2012-03-27 00:14:37 +02:00
Dan McGee
de0f46b947 Use g_message and not g_debug when removing song
When adding or updating a song, we get a log message even if debug is not
enabled. It seems odd that removing a song shouldn't be done at the same log
level; otherwise looking at the log leads you to believe songs are never
removed from the library on update.

Signed-off-by: Dan McGee <dan@archlinux.org>
2012-03-26 17:32:18 +02:00
Dan McGee
1a57fa095f Fix processing of sticker database path
After a previous refactor, the current code fails on paths that need
expansion (e.g, '~/.mpd/sticker.db'), because we are not passing the correct
path to the sticker database code. Pass the expanded (and previously unused)
string instead of the original string.

Signed-off-by: Dan McGee <dan@archlinux.org>
2012-03-26 17:30:06 +02:00
Max Kellermann
167242fec0 output/alsa: add option to enable DSD over USB 2012-03-22 01:30:16 +01:00
Max Kellermann
81208d78ac pcm_dsd: implement DSD to 24 bit USB conversion
Implements the dCS suggested standard:

 http://www.dcsltd.co.uk/page/assets/DSDoverUSB.pdf
2012-03-22 01:14:51 +01:00
Max Kellermann
da8b01771f playlist/soundcloud: libyajl2 uses size_t for string lengths
Fixes build failure on 64 bit.
2012-03-22 01:07:49 +01:00
Max Kellermann
725fbe946b output/alsa: split the frame_size attribute
Make it in_frame_size and out_frame_size, to account for packing.
2012-03-22 01:01:11 +01:00
Max Kellermann
b99ecb4dc9 audio_format: remove the packed S24 format
For simplicity, the MPD core should not have to deal with packing.  It
is rarely used, and those plugins that need it should use the
pcm_export library instead.
2012-03-22 00:42:12 +01:00
Max Kellermann
208a96b211 output/alsa: use pcm_export to pack 24 bit samples 2012-03-22 00:33:59 +01:00
Max Kellermann
43774455cc output/oss: use pcm_export to pack 24 bit samples 2012-03-22 00:33:40 +01:00
Max Kellermann
5b61e077e0 pcm_export: add option "pack"
Converts padded 24 bit samples to packed 24 bit samples.  Will replace
the packed S24 sample format, which is not used internally.
2012-03-22 00:33:40 +01:00
Max Kellermann
921cc3e5db output/oss: remember the real OSS format
Improving oss_reopen() by using the very same value that was used
initially.
2012-03-22 00:33:40 +01:00
Max Kellermann
51dce3d161 output/alsa: simplify setup_format() 2012-03-22 00:29:56 +01:00
Max Kellermann
c10f013fc2 output/alsa: don't pass audio_format to _try_format()
Let the caller configure the audio_format object.
2012-03-22 00:24:56 +01:00
Max Kellermann
2874d68bdb output/alsa: simplify alsa_output_try_format_both()
Merge three functions into one and call get_bitformat() only once.
2012-03-22 00:23:07 +01:00
Max Kellermann
11e83eb7e7 output/oss: move code to oss_probe_sample_format() 2012-03-21 22:28:18 +01:00
Max Kellermann
9ec9a8705e pcm_export: use the byte_reverse library directly
Delete the now-unused pcm_byteswap library, and optimize the
pcm_export_state object.
2012-03-21 21:18:11 +01:00
Max Kellermann
170635e3a6 output/{alsa,oss}: move endian code to new library pcm_export 2012-03-21 21:16:50 +01:00
Max Kellermann
a5d1444ef4 pcm_pack: fix regression in unpack_sample()
Should have been "==", not "!=".
2012-03-21 21:16:46 +01:00
Max Kellermann
55708b39c3 audio_format: DSD_OVER_USB is padded to 32 bit
For simplicity, pad the dCS samples to 32 bit.  Packed 24 bit samples
are rarely used.  This patch does not include a real code change,
because there is no user of DSD_OVER_USB yet.
2012-03-21 19:41:41 +01:00
Max Kellermann
8c5ebdff36 audio_format: remove the reverse_endian attribute
Eliminate support for reverse endian samples from the MPD core.  This
moves a lot of complexity to the plugins that really need it (only
ALSA and CDIO currently).
2012-03-21 19:31:04 +01:00
Max Kellermann
1c84f324a1 output/oss: always receive host byte order samples
Don't use audio_format.reverse_endian.
2012-03-21 19:25:59 +01:00
Max Kellermann
3dba09f339 output/alsa: always receive host byte order samples
Don't use audio_format.reverse_endian.
2012-03-21 19:14:05 +01:00
Max Kellermann
7ebf8e66c9 decoder/pcm: always supply host byte order samples
Don't use audio_format.reverse_endian.
2012-03-21 19:10:57 +01:00
Max Kellermann
62218fe59d test: add unit test for util/byte_reverse.c 2012-03-21 19:08:32 +01:00
Max Kellermann
95d9bb6dfc pcm_byteswap: move code to libutil 2012-03-21 18:58:19 +01:00
Max Kellermann
33986075ef Makefile.am: link src/util/*.c into libutil.a 2012-03-21 18:58:19 +01:00
Max Kellermann
766905ba9f output/alsa: merge alsa_data_free() into destructor 2012-03-21 18:58:11 +01:00
Max Kellermann
a29c64b6c7 audio_format: hack for DSD to USB conversion
Halve the sample rate for *:dsdusb:*.
2012-03-21 10:33:43 +01:00
Max Kellermann
777e1cabc5 test/run_convert: allow the out format to be a mask 2012-03-21 10:33:43 +01:00
Rich Healey
396e97fc94 Fix the build on OSX 2012-03-21 10:32:54 +01:00
Max Kellermann
9c6a4505c8 audio_format: remove the format SAMPLE_FORMAT_DSD_LSBFIRST
This format is unused since the DSDIFF decoder plugin now reverses the
bit order.
2012-03-21 09:06:48 +01:00
Max Kellermann
238c3adad1 decoder/dsdiff: reverse bits to most significant bit first
Allow to remove this complexity from the MPD core.
2012-03-21 09:01:56 +01:00
Max Kellermann
c1d0a8b5ce dsd2pcm: move the bit reversing code to a generic library
Instead of doing run-time initialisation, use a constant lookup table.
2012-03-21 08:44:43 +01:00
Max Kellermann
08ce24ec3f audio_format: basic support for DSD-over-USB 2012-03-19 23:49:29 +01:00
Max Kellermann
79eb7623ef event_pipe, test: explicitly ignore write() return value
Some compilers are very picky, but we really aren't interested in the
return value.
2012-03-19 23:26:47 +01:00
Jonathan Neuschäfer
b9e64d0472 decoder/audiofile: fix compiler warnings with libaudiofile 0.3.3
This might break older versions, I didn't test.
2012-03-19 23:21:12 +01:00
Max Kellermann
4f500149af text_input_stream: detect end-of-file
Fixes endless loop when the last line of a text file was not
terminated (bug 3470).
2012-03-19 23:17:56 +01:00
Robert Vollmert
281b8714ef playlist/soundcloud: support libyajl2
[mk: backwars compatibility and autoconf check]
2012-03-19 21:16:48 +01:00
Max Kellermann
d5be3cce9c text_input_stream: detect end-of-file
Fixes endless loop when the last line of a text file was not
terminated (bug 3470).
2012-03-19 20:37:25 +01:00
Max Kellermann
8dcefaf2e3 test/dump_text_file: debug program for text_input_stream.c 2012-03-19 20:37:25 +01:00
Max Kellermann
48e3432a63 test/run_input: use input_stream_*lock() 2012-03-19 20:37:25 +01:00
Max Kellermann
69d3c611aa util/list: allow typeof() with clang 2012-03-19 20:37:25 +01:00
Max Kellermann
36827e1134 event_pipe, test: explicitly ignore write() return value
Some compilers are very picky, but we really aren't interested in the
return value.
2012-03-19 20:37:25 +01:00
Max Kellermann
351ac4a2c0 command: read arbitrary local files with "lsinfo"
Requires UNIX domain socket connection.
2012-03-06 22:23:10 +01:00
Max Kellermann
36fff59a38 client_file: always allow access if client uid equals mpd uid 2012-03-06 22:22:27 +01:00
Max Kellermann
1e60a4386a playlist_edit: move UID check to client_allow_file() 2012-03-06 22:10:54 +01:00
Max Kellermann
e9f1b53ae6 command, ack: add ack_quark()
To pass ack values around.
2012-03-06 22:08:54 +01:00
Max Kellermann
5016839b90 use g_strerror() instead of strerror()
Make sure we get a UTF-8 encoded string.
2012-03-06 22:06:08 +01:00
Max Kellermann
faf35e6082 command: fix the "DENIED" ACK code
Use ACK_ERROR_PERMISSION instead of ACK_ERROR_NO_EXIST.
2012-03-06 21:37:10 +01:00
Max Kellermann
d07a6edd2f configure.ac: detect libyajl for playlist/soundcloud 2012-03-01 20:18:16 +01:00
Max Kellermann
553d4e9283 playlist/soundcloud: use config_dup_block_string() 2012-03-01 20:11:09 +01:00
Robert Vollmert
7cef52478d A soundcloud playlist plugin.
Requires YAJL to build, and this doesn't include the necessary
automake changes. Can be built using
./configure CFLAGS="-I/usr/include/yajl" LIBS="-lyajl" --enable-soundcloud

Add the following to your config:

playlist_plugin {
        name "soundcloud"
        enabled "true"
        apikey "c4c979fd6f241b5b30431d722af212e8"
}

Then you can stream from soundcloud using calls like:

mpc load soundcloud://track/<track-id>
mpc load soundcloud://playlist/<playlist-id>
mpc load soundcloud://url/http://soundcloud.com/some/track/or/playlist

For the last case, you can leave off the http:// or
http://soundcloud.com/ .
2012-03-01 20:11:09 +01:00
Max Kellermann
e7ce362d22 song_update, udp_server: workarounds for gcc 4.1 warnings
Annoying false positives.
2012-03-01 20:11:09 +01:00
Kurt Van Dijck
c551c8b31b raop_output: fix raop_session inbalance
raop_session_free must be called from raop_output_finish,
not from raop_output_remove.
In raop_output_remove, do close the ntp_server & control port.

Signed-off-by: Kurt Van Dijck <kurt.van.dijck@skynet.be>
2012-03-01 09:51:37 +01:00
Max Kellermann
9c36e71081 decoder/dsdiff: don't convert to PCM
Move the responsibility for the conversion to the PCM library.  This
will allow passing the verbatim DSD samples to an output plugin.
2012-03-01 02:05:40 +01:00
Max Kellermann
c9c57af5f7 pcm_convert: support the DSD format 2012-03-01 02:00:12 +01:00
Max Kellermann
2516496993 audio_format: add DSD sample format
Basic support for Direct Stream Digital.  No conversion yet, and no
decoder/output plugin support.
2012-03-01 01:15:22 +01:00
Max Kellermann
3b565b5f97 pcm_convert: add method _reset()
Resets the libsamplerate state.  Not being used yet.
2012-03-01 00:59:53 +01:00
Avuton Olrich
0742976138 win32: Add a Windows OS resource file and icon 2012-02-23 06:32:30 -08:00
Max Kellermann
1a63663c85 Merge remote branches 'jn/ffmpeg' and 'jn/wsp' 2012-02-15 21:49:20 +01:00
Jonathan Neuschäfer
00a20fc8a5 decoder/ffmpeg: always use AV_VERSION_INT 2012-02-15 21:42:52 +01:00
Jonathan Neuschäfer
6ab4fb368c input/cdio_paranoia: whitespace-fix a comment 2012-02-15 21:22:49 +01:00
Jonathan Neuschäfer
fa39bb0a50 doc/protocol: fix some grammar
(Maybe it should be "A new message is indicated...", I don't know.)
(                                ^^                               )
2012-02-15 21:17:19 +01:00
Max Kellermann
645663cdfe Merge branch 'af' of git://git.musicpd.org/jn/mpd 2012-02-15 21:06:53 +01:00
Jonathan Neuschäfer
ee2bcbb41d decoder/audiofile: fix compiler warnings with libaudiofile 0.3.3
This might break older versions, I didn't test.
2012-02-15 20:52:48 +01:00
Jonathan Neuschäfer
12b4ebf8d4 use audio_output_plugins_for_each's plugin iterator 2012-02-15 20:37:29 +01:00
Jonathan Neuschäfer
8da4750ee2 rtsp_client: strncat -> g_strlcat
The main difference is that strncat takes the maximum number of
characters to copy as its third argument, while g_strlcat takes
the size of the buffer, which is how the code was using strncat.

Incomplete requests may still be constructed as a result of the
reqest buffer filling up.
2012-02-15 20:37:29 +01:00
Jonathan Neuschäfer
d22df2915c main: handle negative strtol return value
size_t is unsigned most of the time, so we can't really use it to
check for negative values. Also handle strtol overflow.
2012-02-15 20:35:06 +01:00
Jonathan Neuschäfer
e77d96cf89 decoder/sidplay: remove unused variable 'ret' 2012-02-15 20:35:05 +01:00
Max Kellermann
ae28ba84d2 command: move code to protocol/argparser.c 2012-02-14 19:13:04 +01:00
Max Kellermann
b3f3b01958 command: use standard error messages in check_int() 2012-02-14 19:02:11 +01:00
Max Kellermann
52e9cab1c1 command: check for empty string after strtol()
An empty string is obviously not a valid integer.
2012-02-14 18:59:41 +01:00
Max Kellermann
1baaaa40cc command: parse unsigned integers and booleans where applicable 2012-02-14 18:57:43 +01:00
Max Kellermann
b8ed420058 command: move functions to protocol/result.c 2012-02-14 18:57:29 +01:00
Max Kellermann
ed16ee3029 command: eliminate local buffer "unknown" 2012-02-14 18:57:12 +01:00
Max Kellermann
7338b16c18 listen: implement systemd socket activation 2012-02-13 21:32:42 +01:00
Max Kellermann
f529441400 server_socket: add method _add_fd() 2012-02-13 21:32:42 +01:00
Max Kellermann
03664d0426 server_socket: move code to set_fd() 2012-02-13 21:32:42 +01:00
Max Kellermann
652cfb7caf zeroconf: skip initialisation if there is no port 2012-02-13 21:05:05 +01:00
Max Kellermann
5540fbaec2 command: new command "config" 2012-02-13 20:30:27 +01:00
Max Kellermann
0a0b473765 mapper: add mapper_get_music_directory()
Shortcut for map_directory_fs(db_get_root()).
2012-02-13 20:10:19 +01:00
Max Kellermann
df2d041483 database: add "pure" attributes 2012-02-13 20:08:50 +01:00
Max Kellermann
ffc6e19548 database: remove obsolete prototype db_check() 2012-02-13 20:08:47 +01:00
Max Kellermann
d874d7661f mapper: add "pure" attributes 2012-02-13 20:06:23 +01:00
Max Kellermann
1d66e714e6 client: add function client_is_local() 2012-02-13 20:05:31 +01:00
Max Kellermann
d98a863b82 client: add "pure" attributes 2012-02-13 20:05:15 +01:00
Max Kellermann
3b6790c7dc command: never print "bad name" in response to "load"
Work around a confusing error message.
2012-02-13 19:51:27 +01:00
Max Kellermann
5ee3a9a9ca playlist_vector: require database lock for all functions 2012-02-13 19:26:04 +01:00
Max Kellermann
dd26fa67f2 playlist_vector: add new playlist to the end of the list
Avoid reversing the order after every update.
2012-02-13 19:26:03 +01:00
Max Kellermann
89f5e60422 directory.h: move DIRECTORY_DIR to directory_save.c 2012-02-13 19:24:17 +01:00
Max Kellermann
c616165f81 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
	src/decoder/ffmpeg_decoder_plugin.c
	test/read_tags.c
2012-02-13 19:15:18 +01:00
Max Kellermann
103832742d decoder/ffmpeg: read the "year" tag
This was disabled when compiled with a new ffmpeg version.  Older
ffmpeg versions used it explicitly, while newer ones may pass it
through from the codec.
2012-02-13 19:05:39 +01:00
Max Kellermann
3e7e0bcb18 test/run_decoder: initialize GThread 2012-02-13 19:00:23 +01:00
Max Kellermann
7d3d8f20ab test/read_tags: call g_thread_init() 2012-02-13 18:37:09 +01:00
Max Kellermann
e1e3ce980a decoder_api: check state before emitting initial seek command
This fixes seeking in the vorbis decoder during MPD startup.
2012-02-13 18:27:43 +01:00
Max Kellermann
7855a32579 pcm_buffer: pcm_buffer_get() never returns NULL
This fixes a bug when libsamplerate returns an empty buffer for a very
small input buffer.  The caller thinks this is an error, bug there is
no GError object.
2012-02-13 18:17:05 +01:00
Max Kellermann
9c92afa5fe output/winmm: remove pointless NULL check
pcm_buffer_get() cannot ever return NULL.
2012-02-13 18:10:36 +01:00
treblid
edac498d03 directory: fix reverse order of child directories
Directories are loaded in reverse order when MPD starts. Only fixed
when doing a rescan.
2012-02-13 14:44:28 +01:00
Max Kellermann
d7d9dbd2c2 playlist/flac: delete this obsolete plugin
The FLAC playlist plugin has been superseded by the "embcue" playlist
plugin, which can read the embedded CUE sheets of all formats.
2012-02-12 19:57:27 +01:00
Max Kellermann
f8eece22c8 playlist/embcue: ignore "FILE", always point to container song file
An embedded CUE sheet must always point to the song file it is
contained in.
2012-02-12 19:48:02 +01:00
Max Kellermann
df563db294 song: add function song_replace_uri() 2012-02-12 19:48:02 +01:00
Max Kellermann
01b0d9eb97 db_print: print extra "playlist" object for embedded CUE sheets
This finally enables the new embedded CUE sheet code: when a song file
contains a playlist, it is printed in the "lsinfo" output, so clients
get to know about this.
2012-02-12 18:41:25 +01:00
Max Kellermann
a7f13d841f song_update: update the "has_playlist" flag 2012-02-12 18:40:55 +01:00
Max Kellermann
686d8bbe69 tag_handler: add new handler that updates has_playlist 2012-02-12 18:40:55 +01:00
Max Kellermann
4b36af4a34 tag: add attribute "has_playlist" 2012-02-12 18:29:05 +01:00
Max Kellermann
4a23a4bfee tag_{ape,id3}: remove the _load() functions
Use _scan() instead, to have more control.
2012-02-12 18:29:05 +01:00
Max Kellermann
ac3ad452c0 playlist_vector: use the list_head library 2012-02-12 17:50:30 +01:00
Max Kellermann
027c01511c update_remove: add header update_remove.h 2012-02-12 17:43:23 +01:00
Max Kellermann
4fdcc0496f update_walk: move code to update_db.c 2012-02-12 17:41:34 +01:00
Max Kellermann
0c4a2bea69 update_walk: move code to update_io.c 2012-02-12 17:00:00 +01:00
Max Kellermann
2ba3401238 update_walk: move code to update_song_file() 2012-02-12 16:50:24 +01:00
Max Kellermann
1735284a2a playlist/embcue: new plugin for reading embedded cue sheets
Parses CUE data from the "CUESHEET" tag.  Needs further integration in
the update thread.
2012-02-12 16:10:20 +01:00
Max Kellermann
8a3192ffc1 decoder/wavpack: bigger tag value buffer
Prepare for big CUESHEET tags.
2012-02-12 16:10:20 +01:00
Max Kellermann
ffea273a28 tag_handler: handle arbitrary name/value pairs
The new method pair() receives an arbitrary name/value pair.  Support
for this is being added to a few decoder plugins.
2012-02-12 13:41:48 +01:00
Max Kellermann
1783aac438 decoder/wavpack: move code to wavpack_scan_tag_item()
Remove clutter from wavpack_scan_file(), and use a (large) fixed
buffer for the tag item.
2012-02-11 19:36:59 +01:00
Max Kellermann
29bf3d2c04 decoder/wavpack: use the tag_table library 2012-02-11 19:34:10 +01:00
Max Kellermann
ee16fc958c decoder/{mikmod,fluidsynth,mp4ff}: adapt to tag_handler API
Fixes build regression.
2012-02-11 19:28:56 +01:00
Max Kellermann
5d73215a8d decoder_plugin: scan tags with callback table
Pass a callback table to scan_file() and scan_stream(), instead of
returning a tag object.
2012-02-11 17:04:29 +01:00
Max Kellermann
b7356bc526 decoder/gme: convert runtime check to assertion
When gme_track_info() returns with success, then the gme_info_t
pointer must be set.
2012-02-11 16:59:24 +01:00
Max Kellermann
8ec8282f38 decoder/ffmpeg: use the tag_table library 2012-02-11 16:39:03 +01:00
Max Kellermann
43b7b98949 decoder/ffmpeg: move code to ffmpeg_metadata.c 2012-02-11 16:37:29 +01:00
Max Kellermann
f791065a98 decoder/ffmpeg: remove AV_VERSION_INT definition
All supported ffmpeg/libav versions have this.
2012-02-11 16:37:25 +01:00
Max Kellermann
d95db28695 decoder/flac: check for errors only after _process_single()
The only other libFLAC call (seek) does not produce fatal errors.
2012-02-11 12:57:18 +01:00
Max Kellermann
851fb16e7c decoder/flac: symmetric FLAC__stream_decoder_finish() calls
Call it in the function that also invokved
FLAC__stream_decoder_init_*().
2012-02-11 12:56:52 +01:00
Max Kellermann
a4cbaafd10 decoder/flac: use error messages from libFLAC 2012-02-11 12:37:24 +01:00
Max Kellermann
c5f2cdb822 decoder/flac: eliminate the remaining "gotos"
https://www.xkcd.com/292/
2012-02-11 12:37:24 +01:00
Max Kellermann
1892d29be0 decoder/{vorbis,flac}: use the tag_table library 2012-02-11 12:37:24 +01:00
Max Kellermann
9e5a49b8cb tag_id3: use the tag_table library for TXXX 2012-02-11 12:37:24 +01:00
Max Kellermann
767ade02f4 tag_table: convert to a struct
The struct is smaller because it is sparse.  Its traversal is also
more efficient.
2012-02-11 12:37:24 +01:00
Max Kellermann
6e05071a47 decoder_api: correct decoder_seek_error() documentation 2012-02-11 12:37:23 +01:00
Max Kellermann
c8a990b9d3 decoder/vorbis: move code to vorbis_comment.c 2012-02-11 10:04:02 +01:00
Max Kellermann
6868ceae9b INSTALL: mention libav 2012-02-11 09:58:06 +01:00
Max Kellermann
cace646346 INSTALL: remove mention of libcue 2012-02-10 08:26:10 +01:00
Max Kellermann
abcc225763 cue_parser: new line based CUE sheet parser
To replace libcue, the unmaintained and crashy library.
2012-02-10 00:12:29 +01:00
Max Kellermann
b9673fc521 command: add optional range parameter to "load" 2012-02-09 23:55:34 +01:00
Max Kellermann
b0ea3f4261 playlist_save: add start/end_index parameters 2012-02-09 23:54:31 +01:00
Max Kellermann
0103219f00 playlist_queue: add start/end_index parameters 2012-02-09 23:44:33 +01:00
Max Kellermann
e15b4f40d6 Merge commit 'release-0.16.7'
Conflicts:
	NEWS
	configure.ac
2012-02-05 18:33:58 +01:00
Avuton Olrich
66235fddff Modify version string to post-release version 0.16.8~git 2012-02-04 14:41:59 -08:00
Avuton Olrich
f9c5d026f4 mpd version 0.16.7 2012-02-04 14:41:59 -08:00
Max Kellermann
c46239af22 Merge branch 'v0.16.x'
Conflicts:
	src/decoder/ffmpeg_decoder_plugin.c
	test/read_tags.c
	test/run_decoder.c
2012-02-04 17:23:53 +01:00
Max Kellermann
48eb3ff8d9 test/run_decoder: initialize the tag_pool library 2012-02-04 17:18:37 +01:00
Max Kellermann
5646dcc791 test/read_tags: initialize the tag_pool library 2012-02-04 14:32:17 +01:00
Max Kellermann
5d9876e338 decoder/ffmpeg: use AV_SAMPLE_FMT_* if available
Implements support for libavcodec 0.9, which removes the compatibility
macros SAMPLE_FMT_*
2012-02-03 09:55:25 +01:00
Max Kellermann
083340a937 decoder/ffmpeg: use sentinel for the ffmpeg_tag_maps table
Minor optimisation.
2012-02-03 09:18:05 +01:00
Max Kellermann
378fa5ee6a decoder/ffmpeg: support all MPD tags
Use the tag_item_names table to look up the names of all MPD tags, and
remove the duplicate entries from ffmpeg_tag_maps.
2012-02-03 09:10:48 +01:00
Max Kellermann
4764daf3c2 decoder/ffmpeg: pass tag_type and name to _copy_metadata()
Allow using this function without the ffmpeg_tag_map struct.
2012-02-03 09:09:18 +01:00
Max Kellermann
6357496d17 decoder/ffmpeg: merge code to _copy_dictionary()
Eliminate some duplicate code.
2012-02-03 09:09:18 +01:00
Max Kellermann
001e2a604b decoder/ffmpeg: add macros emulating AVDictionary
Move the #ifdefs out of _copy_metadata().
2012-02-03 09:02:14 +01:00
Max Kellermann
f370911c15 decoder/ffmpeg: _copy_metadata() returns void
No interest in this return value.
2012-02-03 08:59:26 +01:00
Max Kellermann
ef5cf40fa6 directory: require the caller to lock the db_mutex
Reduce the number of lock/unlock cycles, and make database handling
safer.
2012-02-02 18:06:33 +01:00
Max Kellermann
837bd79b20 db_lock: add assertions 2012-02-02 17:59:51 +01:00
Max Kellermann
3edd4a24af update_walk: use directory_make_child() 2012-02-02 17:59:51 +01:00
Max Kellermann
535a61b5a9 directory: add new objects to the end of the linked list
This was the cause of the reversed ordering when loading a database
file.
2012-02-02 09:59:38 +01:00
Max Kellermann
e87b7daab5 input/soup: use #pragma only with gcc 4.6+
It seems gcc 4.5 does not allow #pragma within function:

 src/input/soup_input_plugin.c:284:9: error: #pragma GCC diagnostic not allowed inside functions
2012-01-29 14:46:05 +01:00
Max Kellermann
f20689519d directory: fix deep path lookup
This commit fixes a major regression in directory_lookup_directory(),
which broke the deep lookup of directories.
2012-01-29 14:42:28 +01:00
Max Kellermann
ee9c460f74 directory: mark unused parameter 2012-01-24 22:27:42 +01:00
Max Kellermann
84ba14fa29 directory: replace songvec with doubly linked list 2012-01-24 22:26:43 +01:00
Max Kellermann
3c75963352 directory: add function directory_get_song(), ...
Wrap songvec_find() and other songvec methods.
2012-01-24 22:26:43 +01:00
Max Kellermann
5f9dd8287c valgrind.suppressions: misc updates 2012-01-24 22:26:43 +01:00
Max Kellermann
d99f074eb7 directory: replace dirvec with doubly linked list
Random access is not needed, and a linked list is easier to manage: we
don't need to (re-)allocate the pointer array.
2012-01-24 20:49:53 +01:00
Max Kellermann
a989140a07 util/list.h: import the Linux kernel's linked list library 2012-01-24 20:49:52 +01:00
Max Kellermann
420a4c163d directory: simplify constructors and clarify API documentation
Pass only the "name" to a directory, instead of the full (relative)
path.
2012-01-24 20:03:18 +01:00
Max Kellermann
1bab735580 dirvec: unlock mutex in dirvec_find() in all branches 2012-01-24 20:02:32 +01:00
Max Kellermann
a0fcd0cf22 dirvec: don't call g_path_get_basename() on parameter
This overhead is completely useless, because no caller expects this
behaviour.
2012-01-24 18:27:00 +01:00
Max Kellermann
5d5c753c74 songvec: move code to songvec_find_pointer() 2012-01-24 18:06:52 +01:00
Max Kellermann
7e7e3eb8d5 songvec: _delete() returns void
The given song must exist, or MPD will abort.  Calling it with an
unknown song is illegal.
2012-01-24 18:06:25 +01:00
Max Kellermann
2e5f8aeba1 refcount: add missing stdbool.h include 2012-01-24 17:16:42 +01:00
Max Kellermann
c2fe961db1 decoder/ffmpeg: remove debug code 2012-01-24 17:15:29 +01:00
Max Kellermann
2a6acc04a1 dirvec: remove unused functions _clear(), _for_each() 2012-01-21 11:32:06 +01:00
Max Kellermann
a467128093 db_lock: new unified lock for songvec and dirvec 2012-01-21 10:51:53 +01:00
Max Kellermann
abf41eb85c .gitignore: add new output files 2012-01-21 10:51:53 +01:00
Max Kellermann
d83dea4463 db/simple: pass the correct GError pointer 2012-01-12 18:59:26 +01:00
Max Kellermann
ec43721c3c Merge branch 'v0.16.x'
Conflicts:
	src/decoder/ffmpeg_decoder_plugin.c
2012-01-12 18:59:21 +01:00
Max Kellermann
39d52762d1 decoder/ffmpeg: check libavutil version for AVDictionaryEntry
Require libavutil 51.5.0.
2012-01-12 18:45:18 +01:00
Max Kellermann
8d45d0d104 decoder/ffmpeg: raise version dependency for avformat_find_stream_info()
This function was added when the libavformat version was 53.2.0, but
the actual release 53.2.0 did not have it.
2012-01-12 18:28:19 +01:00
Max Kellermann
26ec62714c mixer/alsa: listen for external volume changes
Use libasound's polling functions, implement a bridge to GSource /
GPollFD and send idle events to clients when an external program
changes the ALSA mixer volume.
2012-01-05 01:52:40 +01:00
Max Kellermann
7873b5e78b mixer/alsa: move code to alsa_mixer_setup()
Better error handling.
2012-01-05 01:52:05 +01:00
Max Kellermann
1b889c527f mixer/alsa: move code to alsa_mixer_lookup_elem() 2012-01-05 00:52:41 +01:00
Max Kellermann
9937ff8ac0 Merge branch 'v0.16.x'
Conflicts:
	src/decoder/ffmpeg_decoder_plugin.c
	src/input/ffmpeg_input_plugin.c
2012-01-05 00:33:23 +01:00
Max Kellermann
abd1949825 decoder/ffmpeg: support libavformat 0.8 2012-01-05 00:17:56 +01:00
Max Kellermann
4e6bc77a70 decoder/ffmpeg: use avcodec_decode_audio4(), support libavcodec 0.8 2012-01-04 22:10:38 +01:00
Max Kellermann
531948358b decoder/ffmpeg: include libavutil/mathematics.h
Needed for av_rescale_q() in ffmpeg 0.8.
2012-01-04 21:54:54 +01:00
Max Kellermann
0d3ec9c324 configure.ac: disable -Wno-deprecated-declarations 2012-01-04 21:48:30 +01:00
Max Kellermann
21caca4aea decoder/ffmpeg: use avcodec_open2() on newer ffmpeg versions
avcodec_open() has been deprecated.
2012-01-04 21:48:30 +01:00
Max Kellermann
fbf3edf07d decoder/ffpmeg: don't use av_metadata_conv() in ffmpeg 0.7
It's a no-op and deprecated.
2012-01-04 21:47:56 +01:00
Max Kellermann
76fcf25898 decoder/ffmpeg: use AVIOContext instead of ByteIOContext 2012-01-04 21:47:47 +01:00
Max Kellermann
56257f072b input/ffmpeg: use the new AVIOContext API
URLContext is deprecated.
2012-01-04 21:47:19 +01:00
Max Kellermann
44401158e8 input/ffmpeg: define AV_VERSION_INT if not present
Support ancient ffmpeg versions.
2012-01-04 21:47:01 +01:00
Max Kellermann
95b2df8261 output/osx: fix memory leak after AudioUnitSetProperty() failure 2012-01-04 20:47:41 +01:00
Max Kellermann
1ebadf8620 output/osx: implement 32 bit playback 2011-12-24 18:18:42 +01:00
Max Kellermann
9179d9592d output/osx: allocate the device in enable()
Keep the device open as long as the output is enabled, but initialize
it only when playback starts.
2011-12-24 18:15:24 +01:00
Max Kellermann
f208217412 test/run_output: enable and disable the output 2011-12-24 18:15:20 +01:00
Max Kellermann
43c5058682 Merge branch 'v0.16.x' 2011-12-24 18:15:17 +01:00
Max Kellermann
97b4a6b51f output/osx: clear render buffer when there's not enough data
When we don't have enough data, generate some silence, hoping the
input buffer will fill soon.  Reducing the render buffer size is not
legal.
2011-12-24 17:59:36 +01:00
Max Kellermann
f405d27c56 output/osx: remove sleep call from render callback
Blocking inside the render callback is forbidden, and this sleep call
didn't make any sense.
2011-12-24 17:56:10 +01:00
Max Kellermann
99949c8f6f command: new command "seekcur"
For simpler seeking within current song.
2011-12-24 11:20:02 +01:00
Maarten Sebregts
3a9697adf2 Playlist: fix bug in moving after current song
Moving songs using either 'move' or 'moveid' to position -1 (after the
current song) would fail for a song which is just before the current
song.
This patch corrects the check to see if the current song is in the range
to be moved. Since the range is from `start` up to `end` (exclusive) the
check was incorrect, but is now fixed.
2011-12-21 10:29:07 +01:00
Max Kellermann
78c4351e04 output/openal: improve synchronization
This plugin's use of the "Timer" library was wrong; it added the same
amount of virtual data in every iteration in _play(), but did not
actually play something.  This created an artificial, but useless,
delay.  This patch implements the method _cancel(), and implements
hard-coded sleep values.  This is only slightly better, but does not
attempt to look sane.
2011-12-13 22:02:05 +01:00
Max Kellermann
0a427890fe output/openal: move code to inline functions 2011-12-13 22:00:18 +01:00
Max Kellermann
e735abe334 output/openal: use alGetSourcei(AL_BUFFER) to force-unqueue buffers
The implementation of cancel() did not work well: you cannot use
alSourceUnqueueBuffers() to unqueue queued buffers, and our function
openal_unqueue_buffers() left the OpenAL library in a rather undefined
state; nothing was supposed to be queued, but the "filled" variable
was not reset.
2011-12-13 21:59:10 +01:00
Max Kellermann
c0070b2f13 output/openal: make attribute "filled" unsigned 2011-12-13 21:58:13 +01:00
Max Kellermann
cfedc6e9b4 output/openal: remove bogus format check from _open()
The expression "!format" does not make sense, and cannot occur.
2011-12-13 21:58:09 +01:00
Max Kellermann
b66d7f7e0b output/fifo: implement output_plugin method delay() 2011-12-13 21:58:07 +01:00
Max Kellermann
e01df06cd7 output/null: implement output_plugin method delay() 2011-12-13 21:58:02 +01:00
Max Kellermann
6584897b69 output/null: don't initialize the "timer" attribute in _init()
Unnecessary overhead.
2011-12-13 21:57:59 +01:00
Max Kellermann
aa4f45b9a5 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2011-12-13 21:57:44 +01:00
Max Kellermann
96ad5b8444 output/openal: force 16 bit playback, as 8 bit doesn't work
The OpenAL specification says that AL_FORMAT_MONO8 and
AL_FORMAT_STEREO8 expect unsigned 8 bit samples, but MPD uses unsigned
samples.
2011-12-13 21:32:19 +01:00
Max Kellermann
097e5dfbdc timer: fix time unit mixup in timer_delay()
The local variable was already divided by 1000, and the return value
was being divided by 1000 again - doh!  This caused delays in the
httpd output plugin that were too small by three orders of magnitude,
and the buffer was filled too quickly.
2011-12-13 21:02:48 +01:00
Max Kellermann
2ef7ee6ca7 update_walk: print debug message for song_file_load() 2011-12-13 20:26:24 +01:00
Max Kellermann
2685b53b30 configure.ac: suppress warnings in the GLib headers
Replace -I with -isystem in GLIB_CFLAGS.
2011-12-13 20:12:49 +01:00
Max Kellermann
533e4fcdad decoder/mp4ff: work around assertion failure in read() callback
This workaround leads to an infinite loop instead of an assertion
failure, but hey, now it's libmp4ff's fault.
2011-12-13 20:08:31 +01:00
Max Kellermann
006b8fa3f0 pcm_buffer: poison the old buffer before returning it
Make valgrind find more buffer misuses.  Buffer contents are not
persistent, they get invalidated by pcm_buffer_get(), because this
function may allocate a new buffer, but will not copy old data.
2011-12-13 19:55:41 +01:00
Max Kellermann
6a01153ce4 pcm_buffer, output_plugin, ...: include config.h 2011-12-13 19:48:37 +01:00
Max Kellermann
34aab116ae pcm_buffer: eliminate merge conflict fallout 2011-12-13 19:48:33 +01:00
Denis Krjuchkov
33232face9 winmm_output_plugin: fail if wrong device specified instead of using fallback.
Silently choosing default is misleading and can cause hours of investigation.
It's better to fail immediately telling user what is wrong with config.
2011-12-13 19:12:33 +01:00
Denis Krjuchkov
b88b2b3d79 output_init: initialize replay gain filters to NULL in ao_base_init()
If output plugin fails to init it will try to call ao_base_finish() immediately,
which segfaults because replay gain filters are not initialized yet and contain
garbage values.
2011-12-13 19:12:30 +01:00
Max Kellermann
744d729dab input/soup: disable -Wcast-qual to work around libsoup header problem 2011-12-12 10:15:04 +01:00
Avuton Olrich
71b5e43153 configure.ac: Refactor the musepack section
It appears the musepack section has not really been reviewed in some
time, many parts unfunctional, others, just unnecessary.
2011-12-12 10:02:27 +01:00
Avuton Olrich
8459f27312 configure.ac: AC_HAVE_LIBRARY has been depreciated, move to AC_CHECK_LIB 2011-12-12 10:02:15 +01:00
Avuton Olrich
7dfbdef505 configure.ac: Update to methods which autoconf is going to 2011-12-12 10:02:05 +01:00
Avuton Olrich
94386374ff configure.ac: Realphabetize and 80 column the pretty output 2011-12-12 10:02:02 +01:00
Avuton Olrich
f5d3859238 cmdline: Remove duplicate g_free()s 2011-12-12 09:20:00 +01:00
Avuton Olrich
ef39da5973 configure/utils: Add ipv6 support for mingw build 2011-12-12 09:19:34 +01:00
Avuton Olrich
81e8c4bbff gitignore: Add mpd.service 2011-12-12 09:16:51 +01:00
Avuton Olrich
8ca3642429 Modify version string to post-release version 0.16.7~git 2011-12-01 05:44:53 -08:00
Avuton Olrich
1dc000c06a mpd version 0.16.6 2011-12-01 05:44:53 -08:00
Max Kellermann
4f093d5b97 Merge branch 'v0.16.x'
Conflicts:
	Makefile.am
	NEWS
	configure.ac
	src/encoder/flac_encoder.c
	src/log.c
	src/pcm_buffer.c
2011-11-28 11:56:01 +01:00
Max Kellermann
e1b032cbad decoder/ffmpeg: work around bogus channel count
Initialize the audio_format before calling avcodec_open(), because
avcodec_open() will fill bogus values.
2011-11-28 11:39:21 +01:00
Max Kellermann
6f365c30eb mapper: check "r" permission on music directory
Yet another common support case.
2011-11-28 09:57:21 +01:00
Max Kellermann
718e180423 mapper: check "x" permission on music directory
This is a common support case, and hopefully, the new error message
will allow the user to understand the error without requiring support.
2011-11-28 09:51:21 +01:00
Max Kellermann
cead5e5bd7 mapper: fix the bogus "not a directory" error message
Use stat() instead of g_file_test() to detect other types of errors,
such as "permission denied".
2011-11-28 09:50:44 +01:00
Max Kellermann
cf15629aea mapper: move code to check_directory() 2011-11-28 09:35:50 +01:00
Max Kellermann
a727d0bb0b log: print reason for failure 2011-11-28 09:31:43 +01:00
Max Kellermann
0a218ee56a encoder/wave: support packed 24 bit samples
Convert to padded 24 bit samples, instead of falling back to 16 bit.
2011-11-28 09:25:42 +01:00
Max Kellermann
74beefcaf6 encoder/null: use fifo_buffer instead of pcm_buffer
This fixes a buffer corruption bug; pcm_buffer is not designed to be a
persistent buffers, and will discard anything between two consecutive
calls.
2011-11-28 09:23:36 +01:00
Max Kellermann
399a3abefc encoder/wave: use fifo_buffer instead of pcm_buffer
This fixes a buffer corruption bug; pcm_buffer is not designed to be a
persistent buffers, and will discard anything between two consecutive
calls.
2011-11-28 09:23:12 +01:00
Max Kellermann
cee5036aca encoder/flac: use fifo_buffer instead of pcm_buffer
This fixes a buffer corruption bug; pcm_buffer is not designed to be a
persistent buffers, and will discard anything between two consecutive
calls.
2011-11-28 09:21:32 +01:00
Max Kellermann
790823abb4 growing_fifo: new utility library for growing fifo_buffer 2011-11-28 09:11:11 +01:00
Max Kellermann
f546849352 fifo_buffer: add function fifo_buffer_realloc()
For growing FIFO buffers.
2011-11-28 07:45:15 +01:00
Max Kellermann
a85af593f1 fifo_buffer: add functions _capacity() and _available() 2011-11-27 21:11:47 +01:00
Max Kellermann
07067f8b95 pcm_buffer: add assertions 2011-11-27 20:17:52 +01:00
Max Kellermann
a1e824ada0 pcm_buffer: move formula to new function align_8k() 2011-11-27 20:17:14 +01:00
Max Kellermann
f5f1bfbef1 pcm_buffer: un-inline pcm_buffer_get()
This method is too complex for inlining.
2011-11-27 20:17:12 +01:00
Max Kellermann
cd108ba3aa directory: rename attribute "stat" to "have_stat"
"stat" is a macro on mingw32, which is a pretty stupid thing, and this
commit works around this build failure.
2011-11-27 20:15:25 +01:00
Max Kellermann
2bb5bfa74e directory: convert "stat" to a bool 2011-11-27 20:11:45 +01:00
Max Kellermann
624e7a447d stats: explicitly cast "time_t" to "long"
Fixes warning on mingw32.
2011-11-27 20:07:14 +01:00
Max Kellermann
37420c342b io_thread: fix race condition during startup
Ensure that the io.thread variable is set before entering the event
loop.
2011-11-27 19:28:26 +01:00
Max Kellermann
ef40e362c9 decoder_api: cancel initial seek when song is not seekable
Fixes assertion failure.
2011-11-27 19:19:43 +01:00
Avuton Olrich
ef369c2e2b Makefile.am: Add PULSE_LIBS for linking the mixer when compiling with pulse
Commit 3a3158 introduced a small bug where the pulseaudio mixer would not link
with the main binary in some situations.
2011-11-14 05:09:18 -08:00
Denis Krjuchkov
6452461c39 path: autodetect filesystem encoding on Win32
WinAPI explicitly declares filesystem encoding.
It can be determined by GetACP().
Use that instead of Glib routine that always "detects" UTF-8 on Win32,
which is incorrect for MPD case.
2011-10-23 16:29:58 +02:00
Max Kellermann
1e89ca0994 decoder/dsdiff: provide floating point samples
Eliminate the conversion to integer samples, the MPD core can do this
now.
2011-10-20 03:01:31 +02:00
Max Kellermann
92bb10eed8 decoder/wavpack: read float samples as-is, don't convert to integer
For MPD's new floating point support: when a decoded wavpack file
needs to be resampled, don't convert float to int and back to float.
2011-10-20 02:55:05 +02:00
Max Kellermann
8465c5fe0e pcm_format: implement conversion to float 2011-10-20 02:55:05 +02:00
Max Kellermann
42e248a8da pcm_convert: add function pcm_convert_channels()
For future internal use.
2011-10-20 02:55:05 +02:00
Max Kellermann
e71a652985 pcm_mix: implement float samples 2011-10-20 02:36:26 +02:00
Max Kellermann
bfef0fbff3 pcm_volume: implement float samples 2011-10-20 02:33:51 +02:00
Max Kellermann
545685bc32 audio_format: basic support for floating point samples
Support for conversion from float to 16, 24 and 32 bit integer
samples.
2011-10-20 02:32:39 +02:00
Max Kellermann
13ad2b4dc2 pcm_mix: return bool, make unimplemented format non-fatal
Let the caller deal with a failure.
2011-10-20 02:27:41 +02:00
Max Kellermann
d019343017 pcm_volume: pass an "end" pointer instead of a sample count 2011-10-20 02:27:41 +02:00
Max Kellermann
e977ec924c pcm_volume: remove "default" statement
Don't suppress gcc warnings.
2011-10-20 02:24:25 +02:00
Max Kellermann
b7d5652bf6 pcm_volume: "length" is a "size_t", not "int" 2011-10-20 02:24:25 +02:00
Max Kellermann
725e48fce4 pcm_resample: add function pcm_resample_float()
A version of the resampler that doesn't need int->float->int
conversion.
2011-10-20 02:24:25 +02:00
Max Kellermann
43816c268b pcm_format: move "case" code to separate functions
Reduce the mess with local variables inside switch{}.
2011-10-20 02:24:25 +02:00
Max Kellermann
72e80db823 pcm_*: add "restrict" keywords
Allow more compiler optimizations.
2011-10-20 02:24:25 +02:00
Max Kellermann
7b33c343f8 crossfade: include cleanup 2011-10-20 02:24:25 +02:00
Jonathan Neuschäfer
6d0601b99f doc/protocol.xml: the replay gain "auto" mode was added in MPD 0.16 2011-10-19 23:59:44 +02:00
Jonathan Neuschäfer
b6e713711d doc/protocol.xml: document {en,dis}ableoutput's parameter 2011-10-19 23:32:19 +02:00
Max Kellermann
c53edeeb6c pcm_format: pass an "end" pointer instead of a sample count 2011-10-19 22:36:47 +02:00
Max Kellermann
dfb98417b3 pcm_channels: pass an "end" pointer instead of a sample count 2011-10-19 22:17:30 +02:00
Max Kellermann
9716c3a30e pcm_{channels,resample}: pass channel count as integer, not uint8_t
Reduces number of implicit integer conversions.
2011-10-19 22:14:43 +02:00
Max Kellermann
c4c44c4445 pcm_{channels,format}: add alignment assertions 2011-10-19 22:14:08 +02:00
Max Kellermann
0debe9bd6f pcm_utils: add function pcm_end_pointer() 2011-10-19 22:13:23 +02:00
Max Kellermann
f1da118a6c test: add GLib testing compatibility header
Didn't compile on GLib < 2.16.
2011-10-19 21:14:14 +02:00
Max Kellermann
c30c46cd5f configure.ac: define WINVER
Ensure that WINVER is defined early enough, so other system headers
won't fall back to their default value.  Specifically, this solves a
build failure (-Werror) with mingw-w64 ("WINVER redefined").
2011-10-13 09:23:32 +02:00
Max Kellermann
d394017926 decoder_thread: add missing stdio.h include 2011-10-13 09:09:58 +02:00
Max Kellermann
04525c0259 event_pipe: fix WIN32 regression
The event pipe is not a socket, and the patch that introduced
g_io_channel_new_socket() to the event pipe library was wrong.
2011-10-13 09:08:37 +02:00
Max Kellermann
08a0bb756d pcm_byteswap: use "end" pointer instead of buffer size 2011-10-10 10:24:06 +02:00
Max Kellermann
20c6159c04 pcm_dither: pass an "end" pointer instead of a sample count
This is easier and more efficient to loop on, because only two
variables get modified (src and dest).
2011-10-10 10:24:06 +02:00
Max Kellermann
a47e9d1a4b pcm_pack: pass an "end" pointer instead of a sample count 2011-10-10 10:24:05 +02:00
Max Kellermann
e93dd374a4 pcm_byteswap: use GLib byte swapping macros
GLib's macros are implemented with inline assembly, and probably a lot
faster than our naive bit shifting implementation.
2011-10-10 10:24:05 +02:00
Max Kellermann
0847ca4ec2 pcm_{mix,volume}: pass only sample_format to pcm_mix()
The other audio_format attributes are not used.
2011-10-10 10:24:05 +02:00
Max Kellermann
572d8d0cc4 test: add unit test for the PCM library 2011-10-10 10:24:05 +02:00
Max Kellermann
c9a57d354d pcm_buffer: un-inline pcm_buffer_get()
This function is too complex for being inlined everywhere.
2011-10-10 10:13:43 +02:00
Max Kellermann
52b77f6e31 input/cdio_paranoia: pass byte order swapping to the PCM "decoder"
Send another "magic" MIME type when the byte order must be reversed.
This also fixes byte order issues when big-endian was involved (input
data or host byte order) - that was completely broken.
2011-10-10 10:13:43 +02:00
Max Kellermann
4c9782ee28 decoder/pcm: support reverse byte order 2011-10-10 10:13:43 +02:00
Max Kellermann
26225307d3 decoder_api: convert data to host byte order 2011-10-10 10:13:43 +02:00
Max Kellermann
0129d1e158 pcm_convert: support reverse endian input 2011-10-10 10:13:43 +02:00
Max Kellermann
ece6037a1e pcm_byteswap: add function with sample_format overload 2011-10-10 10:13:43 +02:00
Max Kellermann
bea678a7cd audio_format: convert reverse_endian to a "bool" 2011-10-10 10:13:43 +02:00
Max Kellermann
1fb3fbb4de audio_format: un-inline audio_format_mask_apply()
This function is not critical for performance, and the inline
expansion looks too expensive.
2011-10-10 10:13:43 +02:00
Max Kellermann
2c38d19af2 audio_format: add function attributes
For better optimization.
2011-10-10 10:13:43 +02:00
Max Kellermann
311e627463 audio: rename audio.[ch] to audio_config.[ch] 2011-10-10 10:13:43 +02:00
Max Kellermann
8e1e36a0d5 doc/doxygen.conf: enable "quiet" mode 2011-10-10 10:13:43 +02:00
Max Kellermann
db0bb425e7 Makefile.am: cue_tag.c belongs to libplaylist_plugins.a 2011-10-09 18:48:20 +02:00
Max Kellermann
e001dd2d45 Makefile.am: remove redundant GLIB_CFLAGS specifications 2011-10-09 18:45:37 +02:00
Max Kellermann
c38772c97f Makefile.am: add static library libpcm.a 2011-10-09 18:42:32 +02:00
Max Kellermann
3a31589fdd Makefile.am: generate static library from plugins
Compile the plugins only once with the same C flags.
2011-10-09 18:33:02 +02:00
Max Kellermann
460522bb67 configure.ac: enable automake option "silent-rules" 2011-10-09 18:32:57 +02:00
Max Kellermann
176debaf37 Makefile.am: require automake 1.11
Prepare for enabling "silent-rules".
2011-10-09 18:32:55 +02:00
Max Kellermann
072f83b240 configure.ac: use $LIBS instead of $MPD_LIBS 2011-10-09 18:29:25 +02:00
Max Kellermann
cbd6770f2f configure.ac: substitute FAAD_CFLAGS, FAAD_LIBS
Don't use MPC_CFLAGS, MPD_LIBS.
2011-10-09 18:25:09 +02:00
Max Kellermann
0c3a7bcf12 configure.ac: substitute MPCDEC_LIBS, MPCDEC_CFLAGS
Don't use MPD_LIBS, MPC_CFLAGS.
2011-10-09 17:58:36 +02:00
Max Kellermann
389fbaaca2 configure.ac: add variable BZ2_LIBS
Don't use MPD_LIBS.
2011-10-09 17:56:46 +02:00
Max Kellermann
9652efd107 don't define WINVER in *.c files
In a C file, that is too late, because _mingw.h defaults to 0x0502,
and ours would be illegal redefintion.
2011-10-09 17:52:56 +02:00
Max Kellermann
f3ea834322 decoder/{pcm,dsdiff}: add missing stdio.h include 2011-10-09 17:40:37 +02:00
Max Kellermann
02a6a46e86 configure.ac: don't append DESPOTIFY_LIBS to MPD_LIBS
Use DESPOTIFY_LIBS in Makefile.am instead.  Also, use
DESPOTIFY_CFLAGS.
2011-10-09 17:39:24 +02:00
Max Kellermann
75ad90abc7 configure.ac: remove gprof support
gprof is obsolete, it's better to use perfcounters in every aspect.
2011-10-09 17:35:19 +02:00
Max Kellermann
4104593180 configure.ac: use AC_SEARCH_LIBS for socket, gethostbyname, exp
AC_SEARCH_LIBS allows the function to be present in libc.
2011-10-09 17:31:57 +02:00
Max Kellermann
78e1704122 configure.ac: detect syslog() with AC_SEARCH_LIBS
One call to AC_SEARCH_LIBS replaces AC_CHECK_FUNCS and AC_CHECK_LIB.
2011-10-09 17:03:44 +02:00
Max Kellermann
b9e99575ce Merge commit 'release-0.16.5'
Conflicts:
	NEWS
	configure.ac
2011-10-09 16:32:36 +02:00
Avuton Olrich
fa5e06f95d Modify version string to post-release version 0.16.6~git 2011-10-09 04:44:51 -07:00
Avuton Olrich
3041409334 mpd version 0.16.5 2011-10-09 04:44:51 -07:00
Max Kellermann
71536eb412 decoder/wavpack: don't call WavpackGetMode() twice
Use local variable "is_float".
2011-10-08 15:37:47 +02:00
Max Kellermann
fe77230d84 pcm_convert: fix typo in error message 2011-10-08 15:36:55 +02:00
Max Kellermann
accd262561 audio_format: move code to sample_format_size()
Cast to enum sample_format.  Without the cast, it's just a plain
integer, and gcc cannot know that a "case" statement is missing.
2011-10-08 15:04:04 +02:00
Max Kellermann
3057d19cdf pcm_resample_lsr: move common code to lsr_process() 2011-10-08 14:51:26 +02:00
Max Kellermann
8dd83a2cf3 output/roar: move code to _use_audio_format() 2011-10-08 14:51:19 +02:00
Max Kellermann
49b84f9229 db_print: print absolute URI of playlist entries
The protocol mandates that playlist URIs are absolute (i.e. full URI
relative to the music directory, not relative to the parent
directory).  This adds the parameter "directory" to the "playlist"
visitor method.
2011-10-08 14:51:18 +02:00
Max Kellermann
b43bf4dd74 Merge branch 'v0.16.x' 2011-10-08 14:50:44 +02:00
Max Kellermann
5ed0eb51d1 output/openal: auto-fallback to mono if channel count is unsupported
.. instead of failing playback completely.
2011-10-08 14:41:22 +02:00
Max Kellermann
72a1ca3b99 output/alsa: remove "default" case from switch
Allow gcc to warn when a new format isn't supported.
2011-10-08 14:41:11 +02:00
Max Kellermann
14424281a0 pcm_resample: add internal function _lsr_init()
Let the libsamplerate code initialize itself.
2011-10-08 13:32:29 +02:00
Max Kellermann
2b3fd0d4d3 pcm_resample: one-time global initialization
Load the samplerate_converter on MPD startup.  Fail if the converter
name is invalid.
2011-10-08 13:14:29 +02:00
Max Kellermann
894b9cfdb9 decoder/dsdiff: add option "lsbitfirst"
Defaults to "no", which fixes the noise problems.
2011-10-07 10:10:43 +02:00
Max Kellermann
72ff9bd3e6 configure.ac: disable systemd service by default
Defaulting to "with systemd" causes problems for users who install MPD
as an unprivileged user, and it breaks "make distcheck".  It looks
like enabling it by default creates too many practical problems for
unexperienced users.

With --with-systemdsystemunitdir (without a parameter), configure.ac
attempts to auto-detect systemd.
2011-10-07 09:56:38 +02:00
Max Kellermann
7ecbb0454f decoder/dsdiff: add documentation 2011-10-07 06:38:23 +02:00
Max Kellermann
fa7fa2a55f playlist_song: allow references to songs outside the musicdir
When we have an absolute path that's not inside the music directory,
allow loading it anyway, if we're in "secure" mode (i.e. the client is
connected via UNIX socket).
2011-10-06 22:57:14 +02:00
Max Kellermann
5c0576ca55 Merge branch 'v0.16.x'
Conflicts:
	configure.ac
	src/player_control.c
	src/player_thread.c
	src/playlist_song.c
2011-10-06 22:45:02 +02:00
Jesús Bravo Álvarez
039b354490 playlist_song: fix absolute path support in playlists
Right now, a playlist with absolute pathnames can only add songs that
are in the same the directory of the playlist or under it.

If uri is an absolute pathname and base_uri is set,
playlist_check_translate_song() will check that base_uri is a prefix
of uri, excluding every other song in the music directory outside
base_uri.

I think in this case base_uri should be completely ignored (and made
NULL) and uri should just be checked against music root directory.
2011-10-06 22:21:24 +02:00
Max Kellermann
b2f03e76ff player_thread: add flag "output_open", fixes assertion failure
Previously, the condition "defined(play_audio_format)" was used to see
if an output device has been opened, but if the device had failed on
startup, an assertion failure could occur.  This patch adds a separate
flag.
2011-10-06 21:22:48 +02:00
Max Kellermann
63b33b6ec5 player_thread: move code to player_open_output()
Common function that manages "player" attributes after
audio_output_all_open() has returned.
2011-10-06 20:55:52 +02:00
Max Kellermann
23670795db output_control: remove unused prototype _close_locked() 2011-10-06 19:51:37 +02:00
Max Kellermann
8ea6c113b5 player_control: auto-start playback when seeking is requested
Now that the player thread can handle SEEK commands while not (yet)
playing, we can remove the "pc.state" check from pc_seek().
2011-10-06 00:35:54 +02:00
Max Kellermann
37f026a0a6 player_thread: handle SEEK while not playing 2011-10-06 00:35:53 +02:00
Max Kellermann
f67136df19 decoder_api: call _prepare_initial_seek() in decoder_tag()
This checks both conditions: pending and running.  Fixes yet another
assertion failure!
2011-10-06 00:35:53 +02:00
Max Kellermann
e07073ff28 decoder_api: move code to _prepare_initial_seek()
.. and add a few code comments.
2011-10-06 00:35:53 +02:00
Max Kellermann
64b0ba6da7 decoder_control: add attributes start_ms, end_ms
Don't read song.start_ms and song.end_ms, let the player thread manage
this logic instead.
2011-10-05 23:15:22 +02:00
Max Kellermann
99d4ae0c1a decoder_api: don't copy tag to pipe during initial seek
Fixes one more assertion failure.
2011-10-05 22:54:30 +02:00
Max Kellermann
f185b35088 decoder_api: clear initial_seek_running on error
Fixes possible assertion failure.
2011-10-04 22:29:31 +02:00
Max Kellermann
4e909f9411 decoder/dsdiff: new decoder plugin
Doesn't seem to work yet, getting just noise from a test file.
Seeking isn't implemented yet.
2011-10-04 21:41:03 +02:00
Max Kellermann
99f49e266c Makefile.am: build the "dsd2pcm" program 2011-10-04 21:40:59 +02:00
Max Kellermann
0458211ebc dsd2pcm/noiseshape: fix typo in C++ check 2011-10-04 21:40:56 +02:00
Max Kellermann
8a7b9d9f45 dsd2pcm: fix prototypes
Fixes gcc warnings.
2011-10-04 21:40:31 +02:00
Sebastian Gesemann
3fcf463f9e import dsd2pcm_src.zip
[this is the code from dsd2pcm_src.zip, published on a forum by
Sebastian Gesemann.  Upon request, he has given permission to
redistribute and modify his code, without referring to a specific
license. - mk]
2011-10-04 21:34:30 +02:00
Max Kellermann
f77cd63286 audio_format: add constant MAX_CHANNELS
To be used in fixed-size arrays.
2011-10-04 20:41:32 +02:00
Max Kellermann
2378c2d754 configure.ac: add automake conditional HAVE_CXX 2011-10-03 19:28:54 +02:00
Max Kellermann
bbdb4a67e1 test/run_decoder: initialize GThread
Needed for the I/O thread.
2011-10-03 19:28:54 +02:00
Steven Blackburn
21851c0673 Add support for streaming to a DLNA client
The Naim Uniti does not appear to support icecast-style streaming of FLAC
music but does support the codec from a DLNA server. This change looks for
"transferMode.dlna.org: Streaming" in the HTTP request header and responds
with something the Uniti (and hopefully other DLNA clients) accepts.

The only difference in the DLNA streaming mode is the reponse header and
that icecast metadata is disabled. If a client request indicates both modes
are supported, the DLNA mode is preferred (as the Uniti says it supports
both but then rejects a FLAC ICY stream).

Note: This change may be specific to Naim equipment (the only device it was
tested on). E.g. the hardcoding of Content-Length which works but is not a
logically correct value. The change should be backwards-compatible, so
only those clients requesting a DLNA stream will see any difference.
2011-09-30 08:53:09 +02:00
Miklos Vajna
83f6498aac Install systemd service file if systemd is available 2011-09-30 08:37:36 +02:00
Max Kellermann
7e219c362c Merge branch 'v0.16.x'
Conflicts:
	src/player_thread.c
2011-09-22 00:27:34 +02:00
Max Kellermann
525a791987 decoder_api: emulate SEEK command for initial seek to CUE track
When playing a CUE track, the player thread waited for the decoder to
become ready, and then sent a SEEK command to the beginning of the CUE
track.  If that is near the start of the song file, and the track is
short enough, the decoder could have finished decoding already at that
point, and seeking fails.

This commit makes this initial seek more robust: instead of letting
the player thread deal with the difficult timings, let the decoder API
emulate a SEEK command, and return it to the decoder plugin, as soon
as the plugin finishes its initialization.
2011-09-22 00:04:48 +02:00
Max Kellermann
fb19210cfd decoder_internal.h: more API documentation 2011-09-22 00:04:20 +02:00
Jonathan Neuschäfer
203f48d1fd protocol: drop G_GNUC_PURE from client_message_dup 2011-09-21 17:56:07 +02:00
Jonathan Neuschäfer
371c82b2bf utils: mark sockaddr_to_string() as G_GNUC_MALLOC 2011-09-21 17:56:06 +02:00
Dan McGee
8176880173 Simplify setsockopt() casting workaround
On Win32, the third setsockopt parameter has type (char *) while on POSIX
systems it is (void *). However, given that it is a no-op cast to go from a
char pointer to a void pointer, we can cast to a char pointer (with a
possible const modifier) on all platforms and satisfy the compiler.

Signed-off-by: Dan McGee <dan@archlinux.org>
2011-09-21 17:54:44 +02:00
Jonathan Neuschäfer
b0b2c5b3e0 utils: uri.h: fix a typo: "schema" 2011-09-21 17:47:28 +02:00
Max Kellermann
29742d23d3 configure.ac: fix --enable-id3 help string 2011-09-20 22:18:42 +02:00
Max Kellermann
533a6b0240 tcp_connect: generic library for establishing TCP connections 2011-09-20 21:27:17 +02:00
Max Kellermann
0c0400b6fc io_thread: add function _timeout_add()
Same as _timeout_add_seconds(), but this one has millisecond
resolution.
2011-09-20 21:27:17 +02:00
Max Kellermann
2e83af7c21 io_thread: _timeout_add_seconds() returns GSource*
The numeric ID isn't so useful.
2011-09-20 21:26:30 +02:00
Max Kellermann
a3f7947ad2 server_socket: use resolve_host_port() instead of getaddrinfo()
Allow port specification in "bind_to_address" settings.
2011-09-20 21:15:22 +02:00
Max Kellermann
7d9d459ac2 resolver: add function resolve_host_port() 2011-09-20 21:15:05 +02:00
Max Kellermann
3ea1073809 socket_util: move sockaddr_to_string() to resolver.c 2011-09-20 08:49:36 +02:00
Max Kellermann
76a959a578 rtsp_client, output/raop: use close_socket() instead of close() 2011-09-20 08:48:48 +02:00
Max Kellermann
f43873dc5f tcp_socket, udp_server: use g_io_channel_new_socket() 2011-09-20 08:47:42 +02:00
Max Kellermann
921553d7bb Merge branch 'v0.16.x' 2011-09-20 08:47:06 +02:00
Max Kellermann
c476819cb1 fd_util: add function close_socket()
Wrap close(), use closesocket() on WIN32/WinSock.
2011-09-20 08:38:58 +02:00
Max Kellermann
77a56c7c5a fd_util: check HAVE_INOTIFY_INIT in header
Don't provide the prototype if inotify_init() was not detected.
2011-09-20 08:38:17 +02:00
Max Kellermann
46deb7ca82 fd_util: include check.h, verify config.h was included 2011-09-20 08:38:08 +02:00
Max Kellermann
b03f9ece05 glib_socket.h: wrap g_io_channel_*_new() calls portably
The server_socket library (used by the httpd output plugin) didn't
check for WIN32, that's fixed now.
2011-09-20 08:35:25 +02:00
Dan McGee
27946a981f Set socket TCP keepalive option on incoming connections
If a connected host disappears without our knowledge, as can happen over
wireless or a hibernating machine, we continue to hold the port open waiting
for messages. Because we never try to send anything down this now-broken
pipe, the connection will sit idle taking up a slot in our allowed incoming
connections list.

If enough of these happen, an unintended Denial of Service takes place,
where all connection slots are filled with now-broken, never ending
connections. Setting the TCP keepalive option at least allows these to time
out after the default two hours, which is sufficient in the non-malicious
case.

Signed-off-by: Dan McGee <dan@archlinux.org>
2011-09-19 17:11:09 +02:00
Max Kellermann
74617389c8 output_plugin: the plugin allocates the audio_output object
Pass audio_output objects around instead of void pointers.  This will
give some more control to the plugin, and prepares for non-blocking
audio outputs.
2011-09-19 09:41:21 +02:00
Max Kellermann
1d8840412f configure.ac: add option --enable-solaris-output
Allow enabling the plugin explicitly without running Solaris, to test
the build.
2011-09-19 09:39:35 +02:00
Max Kellermann
df1152ee0f configure.ac: fix solaris result display
Wrong variable name.
2011-09-19 09:39:05 +02:00
Max Kellermann
b4a8b8c0d4 Makefile.am: rename SPARSE_SOURCES to SPARSE_SRC
Work around automake warning.
2011-09-19 08:03:31 +02:00
Max Kellermann
ffa9f4b47f output/roar: check return values
Fixes gcc warnings.
2011-09-18 12:07:06 +02:00
Max Kellermann
667e22bbc7 output/roar: unknown volume is -1, not 0 2011-09-18 12:06:46 +02:00
Max Kellermann
d4d838c8bb output/roar: move code to roar_cancel_locked() and others
Wrap the locking code.
2011-09-18 11:51:18 +02:00
Max Kellermann
c61a889c86 output/roar: use GLib memory allocation functions
GLib has a built-in OOM handler.
2011-09-17 20:12:45 +02:00
Max Kellermann
567fe89a77 output/roar: use config_get_block_string() for temporary 2011-09-17 20:11:51 +02:00
Max Kellermann
950772ab8a output/roar: reorder methods 2011-09-17 20:10:26 +02:00
Max Kellermann
0bd0e2a3ec output: rename plugin variables
Consistent naming.
2011-09-17 20:04:18 +02:00
Max Kellermann
47774ce882 Merge branch 'v0.16.x' 2011-09-17 19:59:52 +02:00
Max Kellermann
3c9bcdd347 output: per-plugin header
Move the "extern" declarations from output_list.c, for more type
safety.
2011-09-17 19:51:41 +02:00
Max Kellermann
3934d2d30c output/pulse: don't expose internal struct in public header
Provide _lock() and _unlock() to wrap all accesses from the mixer
plugin.
2011-09-17 19:50:36 +02:00
Max Kellermann
423ce9557a output/raop: don't expose internal structs in public header 2011-09-17 19:44:30 +02:00
Max Kellermann
947848ebf6 output/roar: export volume methods
Use these instead of exposing the internal roar_t struct.
2011-09-17 19:33:51 +02:00
Max Kellermann
5e22fe488e output: rename plugin source files 2011-09-17 08:54:50 +02:00
Max Kellermann
c666cf1c44 output/pulse: move code to _setup_stream() 2011-09-17 08:53:53 +02:00
Tim Harder
79435dbdec decoder/audiofile: include stdio header for SEEK_* defines
The stdio header is no longer pulled in by af_vfs.h in audiofile-0.3.0.
2011-09-17 07:33:42 +02:00
Max Kellermann
27206368da output/pulse: improve locking
Always lock the main loop when operating on PULSE objects.  Document
this.
2011-09-17 07:30:59 +02:00
Max Kellermann
2be245b75e input/soup: wait some more before resuming the stream 2011-09-16 21:50:05 +02:00
Max Kellermann
17927f5c26 input/soup: improve error messages
Copy the reason_phrase from the SoupMessage, and check for transport
errors in the session callback.
2011-09-16 21:50:05 +02:00
Max Kellermann
754f26a97c input_stream: non-blocking I/O
Add GMutex, GCond attributes which will be used by callers to
conditionally wait on the stream.

Remove the (now-useless) plugin method buffer(), wait on GCond
instead.  Lock the input_stream before each method call.  Do the same
with the playlist plugins.
2011-09-16 21:22:13 +02:00
Max Kellermann
29241c4f83 input_plugin: add method check()
To check for errors without reading.  The decoder thread wants to do
that, before it passes the input stream to the plugin.
2011-09-16 21:22:02 +02:00
Max Kellermann
6f655eb9b9 input/{soup,curl}: free unused postponed_error
Fix memory leak.
2011-09-16 21:13:25 +02:00
Max Kellermann
65dfd90141 input/soup: move libsoup calls to the I/O thread
libsoup's asynchronous API is not thread safe.  By moving the calls
into the I/O thread, several crash bugs will be fixed.
2011-09-16 20:34:47 +02:00
Max Kellermann
59abdbd2dd input/soup: wait for _cancel_message() to complete
Add the "complete" attribute, and set it in _session_callback().
_close() waits for it to become true.
2011-09-16 20:34:47 +02:00
Max Kellermann
a6d6873856 input/soup: return real GErrors to the caller
Add attribute postponed_error, pass this GError to the caller.
2011-09-16 11:36:09 +02:00
Max Kellermann
e99df3a3be input/soup: set the "ready" flag on failure
Fix deadlock.
2011-09-16 11:35:02 +02:00
Max Kellermann
8b657255cc input/soup: remove redundant flag "ready"
We'll add proper locking now, and there's no need to carry this
duplicate flag.
2011-09-16 11:34:50 +02:00
Max Kellermann
0e1dc79321 input/soup: report failure in _read()
To report failures to callers who don't use _buffer().
2011-09-16 11:30:56 +02:00
Max Kellermann
0ef15e5fac input/soup: unlock before cancelling the soup message
Avoid recursive deadlock in _session_callback().
2011-09-16 11:30:30 +02:00
Max Kellermann
9ea8a840a9 decoder_api: remove the loop from decoder_read()
This was useless, because input_stream_read() blocks until data is
available.  Calling it in a loop doesn't make sense.
2011-09-16 09:15:10 +02:00
Max Kellermann
7b88089593 decoder_api: move code to decoder_check_cancel_read() 2011-09-16 09:15:10 +02:00
Max Kellermann
b513943893 input/curl: wait some more before resuming the stream
Pausing and resuming after every little chunk adds lots of overhead.
Add a lower level for resuming the stream.
2011-09-16 09:14:29 +02:00
Max Kellermann
edffc56600 input/curl: clear the "paused" flag before resuming
curl_easy_pause(CURLPAUSE_CONT) may have added enough data to go into
pause again.
2011-09-16 09:11:15 +02:00
Max Kellermann
856b0e6886 input/curl: remove _schedule_update()
Call _update_fds() directly.  This is possible because it's only
called from within the I/O thread.
2011-09-16 09:11:09 +02:00
Max Kellermann
bf1eb46b87 input/curl: unlock the mutex for io_thread_call()
Fix deadlock.
2011-09-16 09:10:39 +02:00
Max Kellermann
7e27d660e2 test/test_queue_priority: work around "set but not used" warning 2011-09-16 09:10:39 +02:00
Max Kellermann
53174ea45f input/soup: fix "unused local variable" warnings 2011-09-16 09:10:33 +02:00
Max Kellermann
87b624f5d5 Merge branch 'v0.16.x' 2011-09-16 07:52:39 +02:00
Max Kellermann
443e96381a configure.ac: disable assertions in the non-debugging build
Add -DNDEBUG to AM_CPPFLAGS.
2011-09-16 07:41:41 +02:00
Max Kellermann
1cbba4fc59 input/curl, output/pulse: fix "unused local variable" warnings 2011-09-16 07:41:41 +02:00
Max Kellermann
344b6dd179 configure.ac: enable -Werror for C++ 2011-09-16 07:38:00 +02:00
Max Kellermann
d8c829fa0c configure.ac: pass AM_CXXFLAGS, AM_CPPFLAGS to Makefile.am 2011-09-16 07:35:46 +02:00
Max Kellermann
e1efc71ad3 input_stream: add "nonnull" attributes 2011-09-15 22:40:44 +02:00
Max Kellermann
f804a739b1 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2011-09-15 21:48:33 +02:00
Max Kellermann
2ed870c854 decoder/ffmpeg: flush the codec after seeking
Let the codec start with fresh buffers.  This should fix the remaining
seeking issues.
2011-09-15 21:41:25 +02:00
Max Kellermann
ce35ba9ac9 decoder/ffmpeg: explicitly specify the current stream for seeking
Use AVStream.time_base to convert the decoder_seek_where() value, and
pass the current stream number to av_seek_frame().
2011-09-15 21:35:29 +02:00
Max Kellermann
724a59aaf7 decoder/ffmpeg: don't require key frame for seeking
Use flag AV_TIME_BASE.
2011-09-15 21:32:29 +02:00
Max Kellermann
42d8c2981f decoder/ffmpeg: higher precision timestamps 2011-09-15 21:30:27 +02:00
Max Kellermann
9aa91e0f17 decoder/ffmpeg: move formula to time_from_ffmpeg() 2011-09-15 21:23:48 +02:00
Max Kellermann
5aabee8996 decoder/ffmpeg: add local variable "av_stream"
Code simplification.
2011-09-15 21:14:53 +02:00
Max Kellermann
48a84ca23e input/rewind: copy the MIME type only once
Reduce heap usage by reducing the number of malloc() / free() calls.
2011-09-15 20:24:15 +02:00
Max Kellermann
8751783a1b input/curl: per-request mutex/cond
The global data structures are now lock-free, because they are
accessed only from the I/O thread.  By using per-request locks, we
have finer grained locking, preparing for locks shared with the
client.
2011-09-15 10:24:50 +02:00
Max Kellermann
3a2ec50d5f input/curl: move all libCURL calls to the I/O thread
This adds some overheads for indirect calls to the I/O thread, but
reduces the amount of global locks.  Next step will be switching to
per-request locks.
2011-09-15 09:48:36 +02:00
Max Kellermann
ce9aeed4cb input/file: return NULL instead of "false" 2011-09-15 09:48:36 +02:00
Max Kellermann
f2be6432a9 Makefile.am: allow out-of-tree sparse call 2011-09-15 09:48:36 +02:00
Max Kellermann
e96f8c0444 input/curl: don't set "ready" on _easy_free()
Move the assignment to _request_done(), right before the GCond is
signalled.  This might fix spurious wakeups.
2011-09-15 09:27:16 +02:00
Max Kellermann
2bf3bc3e10 input/curl: add assertions on io_thread_inside() 2011-09-15 09:27:15 +02:00
Max Kellermann
28143f86f9 input/curl: merge _request_abort() into _request_done()
This is a trivial function.  Merge some duplicate code, e.g. the
g_cond_broadcast() call.
2011-09-15 09:27:13 +02:00
Max Kellermann
76ec3d3248 udp_server: disable -Wmissing-field-initializers 2011-09-15 09:25:53 +02:00
Max Kellermann
d0c85a5a96 gcc.h: add macro GCC_CHECK_VERSION 2011-09-15 09:22:48 +02:00
Max Kellermann
46ed717af4 input/curl: API documentation fix 2011-09-15 06:44:20 +02:00
Max Kellermann
ad37c88f80 input_plugin: add method update()
Update the struct attributes, important for facades like the "rewind"
plugin.  To replace buffer().
2011-09-14 22:25:29 +02:00
Max Kellermann
8c6e8a6eb8 input_internal: add assertions 2011-09-14 22:06:57 +02:00
Max Kellermann
dd33317f45 input_stream: move input_stream_init(), _deinit() to _internal.c 2011-09-14 22:01:55 +02:00
Max Kellermann
c344d63fb3 decoder_internal: don't call input_stream_buffer()
This is not necessary since all relevant input plugins have been moved
to the I/O thread, and there is no remaining useful buffer()
implementation.  This also fixes a busy loop when playing radio.
2011-09-14 09:41:27 +02:00
Max Kellermann
62557f4d6b test/read_tags: initialize the tag_pool library 2011-09-13 22:46:47 +02:00
Max Kellermann
9c46cc4ea0 test/read_tags: call g_thread_init()
Needed for the I/O thread.
2011-09-13 22:42:21 +02:00
Max Kellermann
a236a439cc db_print: move code to function db_selection_print()
Use it in handle_lsinfo(), and eliminate some duplicate code.
2011-09-13 22:09:37 +02:00
Max Kellermann
c779e2674a db_visitor: add method playlist() 2011-09-13 22:02:37 +02:00
Max Kellermann
a94d4be466 db_plugin: add method visit() 2011-09-13 21:47:00 +02:00
Max Kellermann
b7d2d4cfe8 database: don't allow uri==NULL
Add nonnull attributes and fix all callers.
2011-09-13 21:39:07 +02:00
Max Kellermann
a6c797ee4b gcc.h: add macro gcc_nonnull 2011-09-13 21:38:27 +02:00
Max Kellermann
3e40b2249f gcc.h: change "mpd_" prefix to "gcc_"
This is specific to gcc, not to mpd.
2011-09-13 21:37:33 +02:00
Max Kellermann
2fe1b5034d db_plugin: add method get_song()
New db_get_song() implementation.
2011-09-13 21:01:35 +02:00
Max Kellermann
b4430839a3 database: generate GError when database is disabled 2011-09-13 20:54:27 +02:00
Max Kellermann
412cf974a4 directory: don't visit "self" in _walk()
Let the caller decide if the current directory should be visited.
2011-09-13 20:44:35 +02:00
Max Kellermann
3fc6beeff0 locate: remove unused function locate_item_new() 2011-09-13 20:44:00 +02:00
Max Kellermann
2ff35c8bfa directory: don't require a "directory" visitor
.. to recurse.  A visitor may not have one, but still be interested in
a recursive search.
2011-09-13 20:44:00 +02:00
Max Kellermann
169db88c20 database: add struct db_visitor
Use this struct for db_walk().
2011-09-13 19:37:28 +02:00
Max Kellermann
ca419c84b8 stored_playlist: return GError, code is playlist_result
Improve error reporting and handling.  command.c gets the new function
print_error(), which sends a GError to the client.
2011-09-11 07:57:50 +02:00
Max Kellermann
aede71b1dc playlist: move enum playlist_result to playlist_error.h
Reduce header dependencies.
2011-09-11 07:55:51 +02:00
Max Kellermann
14d573cbf1 playlist: move PLAYLIST_COMMENT to stored_playlist.c
Only used there.
2011-09-11 07:55:19 +02:00
Max Kellermann
7819aa6b20 db_plugin: introducing a plugin API for the song database
First draft, not really pluggable currently - hard-coded to use the
"simple" plugin, and calls several of its internal functions.

The API is very simple currently, all searches are still performed
over the root "directory" object.  Future changes to the API will move
those search implementations into the plugin, to allow more efficient
implementations, or implementations that don't have the whole tree in
memory all the time.
2011-09-10 07:58:43 +02:00
Max Kellermann
7cc6b63aac database: move code to db_save.c 2011-09-10 07:48:05 +02:00
Max Kellermann
4af6362751 directory_save: pass const pointer to _save() 2011-09-10 07:48:05 +02:00
Max Kellermann
d54075197f tag_internal: add missing tag.h include
For TAG_NUM_OF_ITEM_TYPES.
2011-09-10 07:48:05 +02:00
Max Kellermann
5cce56199b conf: export config_param_free() 2011-09-09 23:59:46 +02:00
Max Kellermann
3cc12817f6 conf: _get_next_param() returns a const pointer
No writers.
2011-09-09 23:59:46 +02:00
Max Kellermann
68875ba600 database: return GError on failure 2011-09-09 23:28:27 +02:00
Max Kellermann
c345c5ebae .gitignore: add doxygen.conf 2011-09-09 23:21:20 +02:00
Max Kellermann
2119a16e24 .gitignore: add doxygen.conf 2011-09-09 23:04:32 +02:00
Max Kellermann
9f5c938ff3 conf: add config_dup_block_path() 2011-09-09 23:01:22 +02:00
Max Kellermann
b42a8d2364 utils: parsePath() returns GError on failure
Better error messages.
2011-09-09 22:55:57 +02:00
Max Kellermann
61fc01e79e utils: pass a const string to parsePath()
Remove the slash hack, allocate memory for the user name.
2011-09-09 22:55:57 +02:00
Max Kellermann
cceaec1d74 utils: eliminate local variable "pos"
Just advance the "path" pointer.
2011-09-09 22:55:57 +02:00
Max Kellermann
8e5f9c8160 conf: turn config_get_path() into config_dup_path()
config_get_path() was somewhat flawed, because it pretended to be a
function, when it really had a side effect.  The second flaw was that
it did not return the parser error, instead it aborted the whole
process, which is bad style.  The new function returns a duplicated
(modified) string that must be freed by the caller, and returns a
GError on failure.
2011-09-09 22:55:57 +02:00
Max Kellermann
c620fd42f4 glib_compat.h: emulate g_prefix_error() 2011-09-09 22:55:57 +02:00
Max Kellermann
2a859f870a log: print detailed errno message on open() failure 2011-09-09 21:53:42 +02:00
Max Kellermann
b680753db8 log: return GError on initialization failure 2011-09-09 21:53:42 +02:00
Max Kellermann
35af940166 conf: get_block_param() returns a const pointer
No caller needs to write.
2011-09-09 21:36:41 +02:00
Max Kellermann
bc0fec0afe conf: move duplicate check to _read_name_value()
config_add_block_param() cannot fail, which makes it easier to use.
2011-09-09 21:36:41 +02:00
Max Kellermann
e3eca82cc3 conf: move code to config_read_name_value()
Reduce indent.
2011-09-09 21:36:35 +02:00
Max Kellermann
e7651d0d0f conf: add gcc optimization attributes 2011-09-09 21:01:19 +02:00
Max Kellermann
5cf4ce9318 pcm_format: fix 32-to-24 bit conversion (the "silence" bug)
D'oh, we were reading 16 bit integers instead of 32 bit integers!
That caused silence when trying to play a 32 bit input file on a 24
bit sound card (e.g. USB sound chips with 24 bit packed samples).
2011-09-08 23:47:32 +02:00
Max Kellermann
6a6f28668f dbUtils: move code to db_print.c 2011-09-06 00:03:51 +02:00
Max Kellermann
dadf1339b5 dbUtils: pass player_control to findAddIn()
Allow calling findAddIn() without a client object.
2011-09-05 23:14:39 +02:00
Max Kellermann
c2c4228722 Merge commit 'release-0.16.4'
Conflicts:
	NEWS
	configure.ac
2011-09-02 06:38:01 +02:00
Avuton Olrich
5469941f2b Modify version string to post-release version 0.16.5~git 2011-09-01 17:58:29 -07:00
Avuton Olrich
e888c9e827 mpd version 0.16.4 2011-09-01 17:58:28 -07:00
Max Kellermann
3d3bca5338 decoder/oggflac: delete this obsolete plugin
libOggFLAC has been deprecated for 5 years now, and we havn't been
testing it for a long time.  Let's delete it.
2011-09-01 19:29:04 +02:00
Max Kellermann
6a3008d7ff Merge branch 'v0.16.x'
Conflicts:
	configure.ac
	src/output_control.c
2011-09-01 19:19:42 +02:00
Max Kellermann
2556449b36 configure.ac: fail if Vorbis was enabled explicitly, but not found
.. and a minor tweak for libFLAC+libogg detection.
2011-09-01 19:02:23 +02:00
Max Kellermann
446f9973cc configure.ac: fail if FLAC was enabled explicitly, but not found 2011-09-01 19:02:22 +02:00
Max Kellermann
596f36bb78 output/osx: don't drain the buffer when closing
Eliminate an unnecessary source of deadlocks.
2011-09-01 18:21:46 +02:00
Max Kellermann
e7abdab58d output/osx: signal the GCond while mutex is locked 2011-09-01 18:21:46 +02:00
Max Kellermann
13cdc9a9f8 configure.ac: auto-detect libmad without pkg-config
The pkg-config file was added by the Debian package maintainers, and
unfortunately, the rest of the world doesn't have it.
2011-09-01 11:06:08 +02:00
Max Kellermann
a1b8806422 configure.ac: fail if libid3tag was enabled explicitly, but not found
Add M4 function MPD_AUTO_PKG_LIB for pkg-config with AC_CHECK_LIB
fallback.
2011-09-01 10:58:36 +02:00
Max Kellermann
e635d47912 configure.ac: use MPD_AUTO_PKG to detect avahi
Don't abort the configure script when avahi could not be
auto-detected.  It previously did, because there was no custom "fail"
action for PKG_CHECK_MODULES.
2011-09-01 10:11:23 +02:00
Max Kellermann
53ac72a878 Makefile.am: use AVAHI_CFLAGS, AVAHI_LIBS
Don't add those to MPD_CFLAGS / MPD_LIBS.
2011-09-01 10:09:46 +02:00
Max Kellermann
2be6184c8d output_all: move _lock_signal() to output_control.c
Better name, better documentation.
2011-09-01 07:59:15 +02:00
Max Kellermann
8b0b4ff086 output_thread: reimplement CANCEL synchronization
The output thread could hang indefinitely after finishing CANCEL,
because it could have missed the signal while the output was not
unlocked in ao_command_finished().

This patch removes the wait() call after CANCEL, and adds the flag
"allow_play" instead.  While this flag is set, playback is skipped.
With this flag, there will not be any excess wait() call after the
pipe has been cleared.

This patch fixes a bug that causes mpd to discontinue playback after
seeking, due to the race condition described above.
2011-09-01 07:13:21 +02:00
Max Kellermann
60f7ff3de5 output/pulse: reset callbacks before closing stream/context
Fixes assertion failure when a stream callback is invoked too late
after a format change.
2011-08-31 21:01:34 +02:00
Max Kellermann
e76c752987 output/pulse: add function _delete_stream()
Merge common code.
2011-08-31 21:01:22 +02:00
Max Kellermann
042c1abc6e output/pulse: use _delete_context()
Eliminate duplicate code.
2011-08-31 20:58:36 +02:00
Max Kellermann
1401621913 output/raop: remove Audio-Jack-Status check
The value of this is not used, the code is commented out - let's get
rid of it.
2011-08-31 20:19:36 +02:00
Max Kellermann
3c034b0a0c output/raop: remove empty function raopcl_stream_connect() 2011-08-31 20:17:24 +02:00
Max Kellermann
395191bd75 rtsp_client: use the I/O thread
Make the code portable.
2011-08-31 08:32:09 +02:00
Max Kellermann
ec7d8fb6bd udp_server: don't use MSG_DONTWAIT on WIN32
Doesn't exist on mingw32.
2011-08-31 08:32:09 +02:00
Max Kellermann
062948b110 mixer/raop: include cleanup 2011-08-31 08:31:26 +02:00
Max Kellermann
7f3dc5f040 output/raop: cast sendto() parameter to void pointer
Fix compilation on mingw32.
2011-08-31 08:30:26 +02:00
Max Kellermann
dd0798a317 rtsp_client: use g_usleep()
usleep() is not portable.
2011-08-31 08:30:26 +02:00
Max Kellermann
9209ccfa40 rtsp_client: allow parameter "kd" to be NULL
When the caller isn't interested in the values.
2011-08-31 08:16:55 +02:00
Max Kellermann
2525d32e17 rtsp_client: don't wait if packet is over due
Check if the time difference is negative.  That would have caused
sleeping forever.
2011-08-31 07:47:01 +02:00
Max Kellermann
f3ac8a7cd9 io_thread: allow _call() from inside the thread 2011-08-31 07:33:07 +02:00
Max Kellermann
f3d95f70e2 rtsp_client: free attribute "kd" in _close()
Fix yet another memory leak.
2011-08-31 07:13:42 +02:00
Max Kellermann
57526067f5 output/raop: move code to raop_session_new()
.. and fix a few memory leaks.
2011-08-30 22:36:54 +02:00
Max Kellermann
0545bab35d valgrind.suppressions: more OpenSSL and other suppressions 2011-08-30 22:33:19 +02:00
Max Kellermann
293836494d output_control: move code to audio_output_destruct()
.. and destruct the output object properly in test/run_output.
2011-08-30 22:28:15 +02:00
Max Kellermann
ae8bda190e test/run_output: clean up after open failure 2011-08-30 22:20:32 +02:00
Max Kellermann
34d9d8abd4 output/raop: merge raopcl_close() into _finish()
.. and fix a double free bug.
2011-08-30 22:20:32 +02:00
Max Kellermann
bd67e986f4 output/raop: free the raop_data object in finish() 2011-08-30 22:02:55 +02:00
Max Kellermann
e587518d85 output/raop: remove from the session when opening fails 2011-08-30 22:00:19 +02:00
Max Kellermann
210b6c38bd output/raop: move code to raop_output_remove() 2011-08-30 21:56:57 +02:00
Max Kellermann
9592c0b466 rtsp_client: increment "dp" after terminating the string
This fixes a bug that caused all values to be an empty string.
2011-08-30 21:33:02 +02:00
Max Kellermann
a33537b2b9 rtsp_client: simplify whitespace elimination
Just move a pointer, don't call strlen() in every iteration.
2011-08-30 21:31:46 +02:00
Max Kellermann
81d5c9757c rtsp_client: check "new_kd" instead of "i"
Eliminate the redundant local variable "i".
2011-08-30 21:30:06 +02:00
Max Kellermann
f34124a50b rtsp_client: move "new_kd" out of the loop
This must persist iterations.
2011-08-30 21:29:19 +02:00
Max Kellermann
74a39c715b ntp_server: move code to udp_server.c 2011-08-30 07:39:05 +02:00
Max Kellermann
195496333b output/raop: move RTSP client code to rtsp_client.c
Restore some of the original file structure from from raop_play.
2011-08-29 11:27:08 +02:00
Max Kellermann
9ccaa90439 ntp_server: use the I/O thread 2011-08-29 11:23:51 +02:00
Max Kellermann
4733c5fef0 io_thread: add function io_thread_quit() 2011-08-29 10:25:04 +02:00
Max Kellermann
a97ddc8cb9 test/run_ntp_server: quit on SIGINT or SIGTERM
Clean up the process before exiting.
2011-08-29 10:18:54 +02:00
Max Kellermann
59a5b000e0 ntp_server: check for select() failures
Fix freeze after signal was handled.
2011-08-29 10:18:54 +02:00
Max Kellermann
d49a2ccb08 ntp_server: fix socket types
Cast recvfrom(), sendto() buffers to "void*" to avoid "char*" /
"unsigned char*" confusion.  Use ssize_t for the return value, and
socklen_t for the socket address size.
2011-08-29 09:52:51 +02:00
Max Kellermann
4a75acb46c io_thread: add function io_thread_run() 2011-08-29 09:52:03 +02:00
Max Kellermann
453368078b configure.ac: add OpenSSL check for RAOP output plugin
Auto-enable the plugin when OpenSSL was found.
2011-08-29 09:39:03 +02:00
Max Kellermann
6e3b643bdf ntp_server: add debug program "run_ntp_server" 2011-08-29 09:39:03 +02:00
Max Kellermann
a769352a74 output/raop: fallback for g_set_error_literal()
This function was added in GLib 2.18.  Make the plugin compatible with
older GLib versions.
2011-08-29 09:39:03 +02:00
Max Kellermann
8a63c27925 output/raop: move NTP code to separate library 2011-08-28 16:44:12 +02:00
Jonathan Neuschäfer
310895f060 rename 'Timer' to 'struct timer' 2011-08-27 11:30:34 +02:00
Jonathan Neuschäfer
4428894aba let doxygen find the source code
[Unfortunately,] @top_srcdir@ is replaced by the package's top-level
directory relative to the directory of the .in file being processed,
e.g. if you unpack the MPD source to /usr/src/mpd, and build it in the
same directory, @top_srcdir@/src/ in doc/doxygen.conf.in will be re-
placed by "../src/", and, as doxygen is invoked from the top directory,
is will expect the source code in /usr/src/src/, which is obviously
wrong.
To work around this problem, this patch changes @top_srcdir@ to
@abs_top_srcdir@, which expands to the absolute path of the top source
directory[1].

[1] http://www.gnu.org/s/hello/manual/autoconf/Preset-Output-Variables.html
2011-08-27 11:30:30 +02:00
Jonathan Neuschäfer
3d12d7de62 doc/developer.xml: change the coing style example return type to int 2011-08-27 11:27:32 +02:00
Jonathan Neuschäfer
87593f95d4 scripts/makedist.sh: fix test usage
Checkbashisms (part of the Debian devscripts) pionted this out.
2011-08-27 11:27:16 +02:00
Max Kellermann
11626e48bf input/curl: implement a hard-coded timeout of 10 seconds
Be sure to stop the operation at some point when the server isn't
responding.
2011-08-26 19:28:09 +02:00
Max Kellermann
4f021cbced input/curl: use the I/O thread
Background buffering and better timeout handling.  This patch sort of
obsoletes the input_plugin method buffer().
2011-08-25 19:20:57 +02:00
Max Kellermann
ba31d176c8 input/curl: eliminate attribute "eof"
Assume the flag is true when the "easy" CURL handle is NULL.  That
way, we don't need to keep track if CURL has sent us the "DONE"
information yet.
2011-08-25 19:20:28 +02:00
Max Kellermann
68edbc3e4a input/curl: release "easy" CURL handle as early as possible
Release it immediately when end-of-file has been reached.  We don't
need that handle anymore, because the rest is delivered from the
buffers.
2011-08-25 19:19:31 +02:00
Max Kellermann
5068227a46 input/curl: move code to input_curl_flush_buffers()
Allow closing the handle while preserving the remaining buffers.
2011-08-25 18:48:05 +02:00
Max Kellermann
f8f3bc89e7 input/curl: pass input_curl to fill_buffer()
Remove a cast.
2011-08-25 18:43:26 +02:00
Max Kellermann
635f7026b0 io_thread: add helper functions 2011-08-25 18:43:14 +02:00
Max Kellermann
0f1e4f0326 io_thread: move global variables into a struct 2011-08-25 18:43:05 +02:00
Max Kellermann
89355edb8a glib_compat.h: add g_timeout_source_new_seconds() 2011-08-25 18:42:44 +02:00
Max Kellermann
37c8f5c1da input/curl: set GError when init() fails
Let the caller know what happened, he's responsible for logging.
2011-08-25 08:43:05 +02:00
Max Kellermann
5bba2df526 input/soup: free all resources in method close() 2011-08-24 19:31:59 +02:00
Max Kellermann
1935694440 valgrind.suppressions: suppress g_resolver_get_default() 2011-08-24 19:31:59 +02:00
Max Kellermann
12dd6ea8bb valgrind.suppressions: suppress g_data_initialize()
This function initializes global variables.
2011-08-24 19:31:59 +02:00
Max Kellermann
a1f922b040 valgrind.suppressions: add libsoup suppressions 2011-08-24 19:31:59 +02:00
Max Kellermann
017cf088a1 valgrind.suppressions: add GType suppressions
libsoup uses GType.
2011-08-24 19:15:59 +02:00
Max Kellermann
df627cc417 valgrind.suppressions: suppress g_intern_static_string() 2011-08-24 19:15:59 +02:00
Max Kellermann
1b20300b73 valgrind.suppressions: use wildcards 2011-08-24 18:47:48 +02:00
Max Kellermann
3b9ffea36f input/soup: new input plugin based on libsoup
To demonstrate the new I/O thread.  libsoup is well-integrated into
the GLib main loop, which made this plugin pretty easy to write.

As a side effect, we have to initialize the I/O thread in all debug
programs that use the input API.
2011-08-24 03:33:49 +02:00
Max Kellermann
e242f3999c io_thread: new thread for non-blocking background I/O
Try to eliminate the remaining blocking I/O.
2011-08-24 02:55:05 +02:00
Max Kellermann
523f89cc8c input/curl: remove obsolete function input_curl_reinit() 2011-08-24 02:55:05 +02:00
Max Kellermann
0575a6d652 output/raop: use GLib byte order macros 2011-08-24 02:19:40 +02:00
Max Kellermann
08b88714e0 output/raop: use fill_int() in fill_time_...()
Eliminate duplicate code.
2011-08-24 02:18:51 +02:00
Max Kellermann
bcaff4b844 output/raop: check if the "host" option is present
Better than dereferencing NULL.
2011-08-24 01:47:31 +02:00
Max Kellermann
82f336a78f output/raop: remove excessive debug messages 2011-08-24 01:47:27 +02:00
Max Kellermann
350aa33022 output/raop: consistently use GError 2011-08-24 01:47:26 +02:00
Max Kellermann
d6290a2f1a output/raop: use GLib heap functions 2011-08-24 01:47:25 +02:00
Max Kellermann
71e9d08863 output/raop: functions that always succeed return void
No point in returning true, and checking that.
2011-08-24 01:47:23 +02:00
Max Kellermann
9729dc7594 output/raop: rtspcl_connect() returns false on error
.. and not -1, which is "true".
2011-08-24 01:47:22 +02:00
Max Kellermann
92c1b8f31e output/raop: error checking in send_control_command() 2011-08-24 01:47:21 +02:00
Max Kellermann
9ffa2604f8 output/raop: make some allocations static
Allocate objects on the stack to reduce heap overhead.
2011-08-24 01:47:20 +02:00
Max Kellermann
03b1fad4d4 output/raop: remove unused local variables 2011-08-24 01:47:18 +02:00
Max Kellermann
72eb4c534f output/raop: make some exec_request parameters const 2011-08-24 01:47:17 +02:00
Max Kellermann
47d936e9cc output/raop: use "char*" for string buffers
Not unsigned char.  Eliminate useless casts.
2011-08-24 01:47:15 +02:00
Max Kellermann
8e08407090 output/raop: make send_control_command() static
Only used internally.
2011-08-24 01:47:14 +02:00
Max Kellermann
c0a4558c62 output/raop: remove useless test_default_device() implementation
This defaults to "false" when the method pointer is NULL.
2011-08-24 01:47:13 +02:00
Max Kellermann
5ecb6fecc4 Merge branch 'v0.16.x' 2011-08-24 01:47:10 +02:00
Max Kellermann
b3df4dc2c9 output/pulse: fix deadlock when the stream was suspended
Check if the stream is suspended; wake up the main loop when it
becomes suspended.
2011-08-23 23:02:13 +02:00
Max Kellermann
3db9ab82ea output/pulse: add assertions 2011-08-23 22:48:22 +02:00
Max Kellermann
2dc3acc5f0 output/pulse: return 0 on error
Not a bool.
2011-08-23 22:48:22 +02:00
Max Kellermann
25686e5bce pulse/output: fix deadlock when resuming the stream
Unlock the mainloop in all code paths.
2011-08-23 22:45:47 +02:00
Max Kellermann
8d70f808d9 input/curl: limit the receive buffer size 2011-08-23 20:46:51 +02:00
Max Kellermann
7c887af1ea output/httpd: add assertions 2011-08-23 18:14:39 +02:00
Max Kellermann
b7f435b50e output/httpd: don't warn on client disconnect
This warning should only be logged when we really received something.
When the client disconnects, G_IO_IN is triggered, and the read
returns G_IO_STATUS_EOF.
2011-08-23 18:02:56 +02:00
Max Kellermann
d3b15f8fda decoder/mpcdec: fix gcc warning
Move the variable "vbr_update_acc" into the #ifdef block.
2011-08-23 17:58:56 +02:00
Jonathan Neuschäfer
eea726740b output/raop: rewrite remove_char_from_string 2011-07-25 11:23:22 +02:00
Max Kellermann
0ea4c970d7 Merge branch 'v0.16.x'
Conflicts:
	src/player_thread.c
	src/playlist_control.c
2011-07-20 21:46:05 +02:00
Max Kellermann
57936a1374 output/raop: use memset() instead of bzero()
There's no bzero() on WIN32.
2011-07-20 21:20:23 +02:00
Max Kellermann
9242fde6b8 output/raop: include winsock.h on WIN32 2011-07-20 21:18:55 +02:00
Max Kellermann
d1f653be65 output/raop: use GMutex instead of pthread_mutex_t
Be portable on WIN32.
2011-07-20 21:11:06 +02:00
Max Kellermann
0035dceb0a output/raop: add missing mutex unlock call in error handler 2011-07-20 21:09:39 +02:00
Max Kellermann
838f7cd210 encoder_plugin: add method pre_tag()
In the "vorbis" plugin, this is a copy of the old flush() method,
while flush() gets a lot of code remove, it just sets the "flush" flag
and nothing else.  It doesn't start a new stream now, which should fix
a few problems in some players.
2011-07-20 20:54:34 +02:00
Max Kellermann
13539961b2 output/httpd: explicitly convert size_t to bool in pause() 2011-07-20 19:16:47 +02:00
Max Kellermann
a26f2ef17d pipe: lock the mutex in music_pipe_size() 2011-07-20 19:05:32 +02:00
Max Kellermann
d97c46bcdc pipe: make read-only functions "pure"
Enable gcc optimizations.
2011-07-20 19:05:26 +02:00
Max Kellermann
2b6542467c output_thread: unlock the mutex while calling cancel()
The method may take longer, and we shouldn't be holding the lock.
2011-07-20 19:05:08 +02:00
Max Kellermann
8fa51faa38 player_thread: lock the player while setting the bite_rate 2011-07-20 19:04:54 +02:00
Max Kellermann
b2175629fd update_walk: apply follow_inside_symlinks to absolute symlinks 2011-07-20 14:15:20 +02:00
Max Kellermann
2e28ed8f81 wavpack: obey all decoder commands, stop at CUE track border
It used to ignore the decoder_data() return value.
2011-07-20 12:54:30 +02:00
Max Kellermann
4c4f8bf02a decoder/wavpack: use the correct integer types
libwavpack provides int32_t samples, and wants uin32_t for sample
counts.
2011-07-20 12:54:22 +02:00
Max Kellermann
e464be5f39 decoder/wavpack: simplify the WavpackUnpackSamples()==0 check
.. and remove one indent level.
2011-07-20 12:32:48 +02:00
Max Kellermann
d7d717f2ce playlist_control: don't resume playback when seeking to another song while paused
Use a shortcut in playlist_seek_song(), don't call
playlist_play_order() because that would reset the "paused" state.
2011-07-20 11:33:51 +02:00
Max Kellermann
d1eeed6a5b output/alsa: fix SIGFPE when alsa announces a period size of 0 2011-07-20 06:54:51 +02:00
Max Kellermann
b159bc0c5f queue: implement song "priorities"
Sorts remaining songs by priority.  This can be used for the
much-demanded "queue feature".
2011-07-19 00:34:33 +02:00
Jonathan Neuschäfer
a222c4879c output/shout: fix a memory leak 2011-07-19 00:24:48 +02:00
Max Kellermann
eb2f413cf0 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2011-07-19 00:24:20 +02:00
Max Kellermann
736fd0e293 decoder/ffmpeg: use avformat_open_input() if available
av_open_input_stream() has been deprecated.
2011-07-18 23:31:47 +02:00
Max Kellermann
6592ca9f88 decoder: use AVDictionary instead of AVMetadata
AVMetadata has been deprecated.
2011-07-18 23:31:31 +02:00
Max Kellermann
762712c756 database: require X_OK on parent directory, not R_OK
For accessing the child of a directory, one needs X_OK on the
directory.
2011-07-18 22:48:07 +02:00
Max Kellermann
73f9e17951 NEWS: fix memory leaks 2011-07-18 22:47:51 +02:00
Jonathan Neuschäfer
7d6a605a85 output/shout: fix a memory leak 2011-07-18 22:04:48 +02:00
Jonathan Neuschäfer
a6a8bdffc3 output/recorder: fix a memory leak 2011-07-18 22:04:10 +02:00
Jonathan Neuschäfer
296085ff23 output/httpd: add missing g_free in error path 2011-07-18 22:04:06 +02:00
Jonathan Neuschäfer
36aa8ce3c9 output/ao: add missing g_free in error path 2011-07-18 22:03:48 +02:00
Jonathan Neuschäfer
c49c69d6ea conf: add missing fclose in error path
This patch seems a bit ugly, maybe it would be a bit cleaner with gotos.
2011-07-18 22:03:40 +02:00
Jonathan Neuschäfer
d5684f7444 sticker: fix a memory leak 2011-07-18 22:03:37 +02:00
Jonathan Neuschäfer
affb4bd923 ape: add missing g_free in error path 2011-07-18 22:03:34 +02:00
Max Kellermann
65772a74e0 configure: correct avahi/bonjour state on result page
Was always displayed as "no", even if one was found.
2011-07-03 15:42:22 +02:00
Max Kellermann
cca2c2f4ca test/run_filter: remove unused variable "frame_size" 2011-07-03 15:21:40 +02:00
Max Kellermann
52e2fa91c4 test/read_conf: make variables more local 2011-07-03 15:20:39 +02:00
Max Kellermann
dca405a746 test/read_conf: fix -Wunused-but-set-variable 2011-07-03 15:20:28 +02:00
Skottish
e54748d355 decoder/ffmpeg: use AVIO_FLAG_READ on newer ffmpeg versions
FFmpeg/libav have dropped AVIO_RDONLY in favor of AVIO_FLAG_READ. This
patch fixes that in MPD.
2011-07-03 15:17:44 +02:00
Jonathan Ballet
3680a6bbbb doc/protocol: add some missing specifications 2011-07-03 15:05:04 +02:00
Max Kellermann
6aa6a9c272 decoder/flac: validate the sample rate when scanning the tag
Don't calculate the song duration when the sample rate is 0 (division
by zero crash).
2011-07-03 14:57:56 +02:00
oblique
8d1c7ca206 ffmpeg: workaround for semantic API change in recent ffmpeg versions 2011-07-03 14:54:56 +02:00
Tony Miller
52b8e0f9ec doc/user: Typo in playlist plugin documentation, 'playlist plugin' not 'filter'.
This patch fixes a typo in doc/user about playlist plugins.

Its in the top commit in my repository in a branch called 'doc_fix':
git://github.com/mcfiredrill/mpd.git
2011-07-03 14:53:37 +02:00
Max Kellermann
08e2e2e791 fd_util: add function socketpair_cloexec_nonblock() 2011-07-01 10:50:15 +02:00
Avuton Olrich
3c4f4793b5 Modify version string to post-release version 0.16.4~git 2011-06-04 07:37:34 -07:00
Avuton Olrich
e2950a7e4d mpd version 0.16.3 2011-06-04 07:37:33 -07:00
Max Kellermann
531c0067ec Makefile.am: distribute client_idle.h 2011-06-03 17:27:43 +02:00
Max Kellermann
e228caaca6 Merge branch 'v0.16.x'
Conflicts:
	src/decoder/ffmpeg_decoder_plugin.c
2011-06-03 16:58:09 +02: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
Qball Cow
9ac8f89b1d cue_tag: show CUE track numbers 2011-05-09 21:26:36 +02:00
Max Kellermann
c6a72a14ac decoder/ffpmeg: don't use av_metadata_conv() in ffmpeg 0.7
It's a no-op and deprecated.
2011-05-09 21:24:18 +02:00
Max Kellermann
c74edd0e33 decoder/ffmpeg: use AVIOContext instead of ByteIOContext 2011-05-09 21:23:58 +02:00
Max Kellermann
98acf3f281 input/ffmpeg: use the new AVIOContext API
URLContext is deprecated.
2011-05-09 21:23:24 +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
fe30db935b 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-04-12 08:20:35 +02:00
Max Kellermann
6303d54cbb decoder/ffmpeg: make variables more local 2011-04-12 08:17:30 +02:00
Anton Khirnov
9d91aa23e6 decoder/ffmpeg: drop support for pre-0.5 ffmpeg
All modern distros ship 0.5, so there's no need to support old and buggy
ffmpeg versions.
2011-04-12 08:14:14 +02:00
Max Kellermann
c2ada39fd3 Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2011-04-12 08:11:33 +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
Simon Kagstrom
77b6e27500 playlist: Despotify plugin: Correct init in daemon mode
There is a global despotify session, so it should not be initialized
until needed.
2011-04-12 07:28:00 +02:00
Simon Kagstrom
99640171e2 doc: Add despotify user documentation 2011-04-12 07:27:59 +02:00
Simon Kagstrom
38b3ab791f doc: INSTALL: Add despotify dependencies 2011-04-12 07:27:59 +02:00
Simon Kagstrom
a86fc52eea configure.ac: Correct error message for missing despotify package 2011-04-12 07:27:59 +02:00
Jonathan Neuschäfer
6d3ed3f16f fix common misspellings
These fixes were mostly generated with `codespell' [0] and manually
reviewed.

[0] http://git.profusion.mobi/cgit.cgi/lucas/codespell/
2011-03-31 21:46:01 +02:00
Simon Kagstrom
be798998bf build: Add despotify to build system 2011-03-29 17:01:16 +02:00
Simon Kagstrom
c3b425d570 doc: Add configuration help for despotify 2011-03-29 17:01:16 +02:00
Simon Kagstrom
a25743875f playlist: Add despotify playlist plugin
For spotify playlists or tracks. Uses a spt uri, so with mpc you can
add playlists with

  mpc load spt://spotify:user:simon.kagstrom:playlist:3SUwkOe5VbVHysZcidEZtH
2011-03-29 17:01:16 +02:00
Simon Kagstrom
124d1a5942 input: Add despotify input plugin
For Spotify tracks. Uses a spt URI, so with mpc you can play tracks
with e.g.,

  mpc add spt://spotify:track:5qENVY0YEdZ7fiuOax70x1
  mpc play

Uses the pcm_decoder_plugin for the output
2011-03-29 17:01:16 +02:00
Simon Kagstrom
eec77b3ae7 despotify: Add support utilities
Used to connect and authenticate to despotify. Provides a singleton
session and a desptoify-track-to-tags function.
2011-03-29 17:01:16 +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
640bac1aa4 decoder: PCM decoder: Inherit seekable from the input stream
E.g., spotify isn't seekable.
2011-03-23 22:13:11 +01:00
Simon Kagstrom
0b12fae84d decoder: PCM decoder: Break loop if EOF is encountered
Otherwise the song playing might go on forever.
2011-03-23 22:13:08 +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
Hans-Kristian Arntzen
d9353c4fd3 Remove unused headers in Roar plugin.
Should fix build errors for Win32.
2011-03-23 21:59:22 +01:00
Max Kellermann
0c9fc2f809 Merge commit 'release-0.16.2'
Conflicts:
	Makefile.am
	NEWS
	configure.ac
2011-03-19 09:58:07 +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
Hans-Kristian Arntzen
1a954748a0 RoarAudio output plugin 2011-03-16 17:57:47 +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
2abad0f479 command: "update" and "rescan" need only "CONTROL" permission
From http://bugs.debian.org/513291

 "In mpd.conf, the "admin" permission covers updating the db and
 killing mpd.

 "Since there are quite some usecases in which the user can upload
 music to the mpd's directory by means of anonymous FTP or so, it is
 desirable that any user may issue a db update, while killing the mpd
 should not be possible.

 "I'd suggest to remove the db update from the admin group and either
 add it to "control" or an own group."
2011-02-27 23:35:00 +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
2fb40fe728 playlist_state: add option "restore_paused"
When set, MPD will not auto-start playback on startup; it will be in
"paused" state.
2011-02-23 09:10:23 +01:00
Max Kellermann
b57330cf75 playlist_state: declare local variable as enum 2011-02-23 09:10:23 +01:00
Max Kellermann
8cd91fabf9 configure.ac: disable -Wno-deprecated-declarations 2011-02-23 09:01:53 +01:00
Max Kellermann
e0580ee385 configure.ac: protocol version 0.17
The client-to-client protocol was added, and that justifies increasing
the protocol version.
2011-02-22 09:16:32 +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
144d092637 output/shout: add possibility to set url
Added a new optional parameter for the shout plugin called "url".
2011-02-09 22:42:51 +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
Thomas Jansen
2bde9afdb9 configure.ac: fix copy&paste error 2011-01-29 13:49:32 +01:00
Max Kellermann
f8b09c194f protocol: support client-to-client communication 2011-01-29 10:43:54 +01:00
Max Kellermann
0e69ad32c1 client_idle: export client_idle_add() 2011-01-29 10:43:54 +01:00
Max Kellermann
9b4e14df71 client_idle: add header client_idle.h 2011-01-29 10:43:54 +01:00
Max Kellermann
03f7803f26 test/read_mixer: add workaround for missing RAOP symbols 2011-01-29 10:43:54 +01:00
Max Kellermann
c6cbcc2c25 copyright year 2011 2011-01-29 10:13:54 +01:00
Ian Zimmerman
27aa34d4ae input/curl: enable CURLOPT_NETRC
I wanted mpd to play a mp3 stream from a music website.  The stream is
only available to subscribers, which restriction is enforced through
normal http authentication.  However, the URL I get from the website
is not the final URL of the stream, but a generic URL which points to
the real one through a redirect (code 301).  Thus, I cannot predict
the final URL, and so I cannot use the username:password hack to force
the authentication, and mpd (libcurl on mpds behalf) fails to grab the
stream.

libcurl allows the option CURLOPT_NETRC to be set and then the
credentials can be stored in the good old .netrc file (in this case it
would be ~mpd/.netrc, of course).  But mpd doesn't set this option.  I
think it should.
2011-01-29 08:43:30 +01:00
Dustin Puckett
79e0db4ca0 output/raop: new output plugin
Remote Audio Output Protocol (RAOP), for Apple devices.
2011-01-28 21:17:09 +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
Yuriy Kaminskiy
9ae3acf2e7 mpg123 decoder: implement seeking 2011-01-21 15:37:08 +01:00
Yuriy Kaminskiy
731ea9b489 mpg123 decoder: report bitrate 2011-01-21 15:37:08 +01:00
Max Kellermann
18b30b5019 decoder_thread: fix assertion failure at song end
Don't finish the current command twice.

This bug was never noticed, but was revealed by a new assertion check.
2011-01-16 17:52: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
Max Kellermann
24d51b9d14 doc: add a list of encoder plugins 2011-01-10 23:13:01 +01:00
Max Kellermann
a1edc199df output_control: document internal functions 2011-01-10 22:16:44 +01:00
Max Kellermann
db4aa81528 output_control: move code to ao_lock_command() 2011-01-10 21:54:43 +01:00
Max Kellermann
319ba94a52 output_control: ao_command() calls ao_command_async()
Merge some code.
2011-01-10 21:52:38 +01:00
Max Kellermann
1025f0be91 update_remove: use plain GCond instead of notify
GMutex/GCond guarantee that the access to removed_song is protected.
2011-01-10 21:40:15 +01:00
Max Kellermann
77d3b5e8f1 include cleanup 2011-01-10 21:38:11 +01:00
Max Kellermann
a0ad96a787 decoder_control: store GCond object, not a player_control
Remove the decoder dependency on player_control.  All player_control
was needed for is to signal the player thread, and we can do that with
a simple GCond as well.
2011-01-10 21:27:43 +01:00
Max Kellermann
39c5af5dbc decoder_thread: move code to decoder_command_finished_locked() 2011-01-10 21:08:16 +01:00
Max Kellermann
acca6a799b decoder_control: remove unused function dc_command_wait()
Only dc_command_wait_locked() is really being used.
2011-01-10 21:08:16 +01:00
Max Kellermann
b77e62260a decoder_control: replace dc_init() with dc_new()
dc_new() allocates the object and returns it.  dc_free() frees it
(replaces dc_deinit()).
2011-01-10 20:46:04 +01:00
Max Kellermann
b6995ca011 player_control: removed the global variable "pc"
Allocate a player_control object where needed, and pass it around.
Each "client" object is associated with a "player_control" instance.

This prepares multi-player support.
2011-01-10 19:46:23 +01:00
Max Kellermann
715844fd08 dbUtils: don't use directoryAddSongToPlaylist() twice
In findAddInDirectory(), call playlist_append_song() directly, to have
some more type checking.
2011-01-10 19:46:14 +01:00
Max Kellermann
2b29ca796e Merge commit 'release-0.16.1'
Conflicts:
	NEWS
2011-01-10 11:47:14 +01:00
Avuton Olrich
44b4b50949 Modify version string to post-release version 0.16.2~git 2011-01-09 18:00:12 -08:00
Max Kellermann
5184008812 input_init: add assertions on completeness of plugins 2011-01-08 18:27:57 +01:00
Max Kellermann
cf696ce443 input/cdio_paranoia: add module name
Seems like we forgot to give this module a name...  this can crash MPD
on startup.
2011-01-08 18:27:57 +01:00
Max Kellermann
1a2ea4c06c Merge branch 'v0.16.x'
Conflicts:
	NEWS
	configure.ac
2011-01-07 23:52:23 +01:00
Anton Khirnov
a800afcbf8 docs: mention 'sticker' idle event 2011-01-05 13:03:17 +01:00
Ben Kibbey
ff4534613a Build fix for Linux. Define _GNU_SOURCE in src/server_socket.c. 2010-12-27 04:36:23 +01:00
Max Kellermann
b8fe2c74bc Makefile.am: generate doxygen.conf
Don't create a modified copy for out-of-tree builds.
2010-12-24 00:25:31 +01:00
Max Kellermann
be3b5199b0 stored_playlist: remove database lookups from spl_load()
Don't look up songs in the database, no caller needs this.
2010-12-23 16:25:37 +01:00
Max Kellermann
d849a40af6 stored_playlist: ignore empty lines 2010-12-23 16:25:22 +01:00
Max Kellermann
4f48c10312 stored_playlist: use the text_file library to read lines 2010-12-23 16:25:05 +01:00
Max Kellermann
5274fee8a7 playlist_song: add flag "secure"
Optionally allow all local files.

"Insecure" mode is used for printing playlists.
2010-12-23 16:24:00 +01:00
Max Kellermann
5462f34ed0 string_util: add function strchug_fast()
Replace g_strchug() calls with a cheaper implementation.
2010-12-23 16:23:20 +01:00
Max Kellermann
0958ed5844 utils: move string_array_contains() to string_util.c 2010-12-23 16:23:04 +01:00
Max Kellermann
e3cba18532 decoder: new "pcm" decoder plugin
Just there to support the "cdio_paranoia" input plugin.
2010-12-22 09:48:48 +01:00
Max Kellermann
9bf7fde49f configure.ac: hook the cdio_paranoia input plugin 2010-12-22 09:44:02 +01:00
Max Kellermann
4783ebc918 input/cdda: rename plugin to "cdio_paranoia" 2010-12-22 09:43:57 +01:00
Max Kellermann
8bda52783b input/cdda: support reading the whole disc 2010-12-22 09:43:53 +01:00
Max Kellermann
07feec7ea6 input/cdda: remove unused function input_cdda_archive_extract_trackno() 2010-12-22 09:43:49 +01:00
Max Kellermann
e7471f589a input/cdda: import missing pcm16_to_wave() from the wave encoder 2010-12-22 09:43:47 +01:00
Max Kellermann
24208be5cf input/cdda: implement parse_cdda_uri()
Was missing.
2010-12-22 09:43:41 +01:00
Max Kellermann
8db5f66498 input/cdda: call input_cdda_close() with an input_stream pointer
Another build fix.
2010-12-22 09:43:27 +01:00
Max Kellermann
be670bfd1f input/cdda: move code to cdda_detect_drive() 2010-12-22 09:43:20 +01:00
Max Kellermann
19acf090ed input/cdda: remove newlines from error messages 2010-12-22 09:43:16 +01:00
Max Kellermann
2de7f6b457 input/cdda: remove debug code 2010-12-22 09:42:10 +01:00
Max Kellermann
a2e265e9a2 input/cdda: some general build failure fixes 2010-12-22 07:44:56 +01:00
Viliam Mateicka
28d7b29d72 input_cdda_plugin: new plugin to handle cdda:// protocol to access CD-DA audio CD's 2010-12-22 07:36:14 +01:00
Greg Ward
9cb4aaf3c2 osx_output: always pass OS X result code to g_set_error().
Should be safe on OS X 10.4 (32-bit), since Apple's OSStatus boils
down to "signed long", and g_set_error() takes gint, which is really
just "int".  Assigning "signed long" to "int" on 32-bit Unix should be
just fine, since both are signed 32-bit ints.

No idea if this is safe on 64-bit OS X.
2010-12-21 07:37:54 +01:00
Greg Ward
80dc602193 osx_output: allow user to specify other audio devices.
Add new config parameter 'device' to audio_output type "osx":
- if not supplied or set to "default", open default device
- if set to "system", open system device
- otherwise 'device' should be an audio device name: mpd will find and
  open the specified audio device, falling back to the default
  device if it's not found
2010-12-21 07:36:28 +01:00
Avuton Olrich
c7f5a87258 Modify version string to post-release version 0.17~git 2010-12-11 04:19:49 -08:00
601 changed files with 28009 additions and 10154 deletions
.gitignoreINSTALLMakefile.amNEWSautogen.shconfigure.ac
doc
m4
mpd.service.in
scripts
src
AudioCompress
ack.haiff.caiff.hape.cape.h
archive
archive_api.carchive_api.harchive_internal.harchive_list.carchive_list.harchive_plugin.carchive_plugin.haudio_check.caudio_check.haudio_config.caudio_config.haudio_format.caudio_format.haudio_parser.caudio_parser.hbuffer.cbuffer.hcheck.hchunk.cchunk.hclient.cclient.hclient_event.cclient_expire.cclient_file.cclient_file.hclient_global.cclient_idle.cclient_idle.hclient_internal.hclient_list.cclient_message.cclient_message.hclient_new.cclient_process.cclient_read.cclient_subscribe.cclient_subscribe.hclient_write.cclock.cclock.hcmdline.ccmdline.hcommand.ccommand.hconf.cconf.hcrossfade.ccrossfade.h
cue
daemon.cdaemon.hdatabase.cdatabase.h
db
dbUtils.cdbUtils.hdb_error.hdb_internal.hdb_lock.cdb_lock.hdb_plugin.hdb_print.cdb_print.hdb_save.cdb_save.hdb_selection.hdb_visitor.h
decoder
decoder_api.cdecoder_api.hdecoder_buffer.cdecoder_buffer.hdecoder_command.hdecoder_control.cdecoder_control.hdecoder_internal.cdecoder_internal.hdecoder_list.cdecoder_list.hdecoder_plugin.cdecoder_plugin.hdecoder_print.cdecoder_print.hdecoder_thread.cdecoder_thread.hdespotify_utils.cdespotify_utils.hdirectory.cdirectory.hdirectory_print.cdirectory_save.cdirectory_save.hdirvec.c
dsd2pcm
dummy.cxx
encoder
encoder_api.hencoder_list.cencoder_list.hencoder_plugin.hevent_pipe.cevent_pipe.hexclude.cexclude.hfd_util.cfd_util.hfifo_buffer.cfifo_buffer.h
filter
filter_config.cfilter_config.hfilter_internal.hfilter_plugin.cfilter_plugin.hfilter_registry.cfilter_registry.hgcc.hglib_compat.hglib_socket.hgrowing_fifo.cgrowing_fifo.hicy_metadata.cicy_metadata.hicy_server.cicy_server.hidle.cidle.hinotify_queue.cinotify_queue.hinotify_source.cinotify_source.hinotify_update.cinotify_update.h
input
input_init.cinput_init.hinput_internal.cinput_internal.hinput_plugin.hinput_registry.cinput_registry.hinput_stream.cinput_stream.hio_thread.cio_thread.hlisten.clisten.hlocate.clocate.hlog.clog.hls.cls.hmain.cmain.hmain_win32.cmapper.cmapper.h
mixer
mixer_all.cmixer_all.hmixer_api.cmixer_api.hmixer_control.cmixer_control.hmixer_list.hmixer_plugin.hmixer_type.cmixer_type.hmpd_error.hnotify.cnotify.hopen.h
output
output_all.coutput_all.houtput_api.houtput_command.coutput_command.houtput_control.coutput_control.houtput_finish.coutput_init.coutput_internal.houtput_list.coutput_list.houtput_plugin.coutput_plugin.houtput_print.coutput_print.houtput_state.coutput_state.houtput_thread.coutput_thread.hpage.cpage.hpath.cpath.hpcm_buffer.cpcm_buffer.hpcm_byteswap.cpcm_byteswap.hpcm_channels.cpcm_channels.hpcm_convert.cpcm_convert.hpcm_dither.cpcm_dither.hpcm_dsd.cpcm_dsd.hpcm_dsd_usb.cpcm_dsd_usb.hpcm_export.cpcm_export.hpcm_format.cpcm_format.hpcm_mix.cpcm_mix.hpcm_pack.cpcm_pack.hpcm_prng.hpcm_resample.cpcm_resample.hpcm_resample_fallback.cpcm_resample_internal.hpcm_resample_libsamplerate.cpcm_utils.hpcm_volume.cpcm_volume.hpermission.cpermission.hpipe.cpipe.hplayer_control.cplayer_control.hplayer_thread.cplayer_thread.hplaylist.cplaylist.h
playlist
playlist_any.cplaylist_any.hplaylist_control.cplaylist_database.cplaylist_database.hplaylist_edit.cplaylist_error.hplaylist_global.cplaylist_internal.hplaylist_list.cplaylist_list.hplaylist_mapper.cplaylist_mapper.hplaylist_plugin.hplaylist_print.cplaylist_print.hplaylist_queue.cplaylist_queue.hplaylist_save.cplaylist_save.hplaylist_song.cplaylist_song.hplaylist_state.cplaylist_state.hplaylist_vector.cplaylist_vector.hpoison.h
protocol
queue.cqueue.hqueue_print.cqueue_print.hqueue_save.cqueue_save.hrefcount.hreplay_gain_ape.creplay_gain_ape.hreplay_gain_config.creplay_gain_config.hreplay_gain_info.creplay_gain_info.hresolver.cresolver.hriff.criff.hserver_socket.cserver_socket.hsig_handlers.csig_handlers.hsocket_util.csocket_util.hsong.csong.hsong_print.csong_print.hsong_save.csong_save.hsong_sort.csong_sort.hsong_sticker.csong_sticker.hsong_update.cstate_file.cstate_file.hstats.cstats.hsticker.csticker.hsticker_print.csticker_print.hstored_playlist.cstored_playlist.hstring_util.cstring_util.hstrset.cstrset.htag.ctag.htag_ape.ctag_ape.htag_file.ctag_file.htag_handler.ctag_handler.htag_id3.ctag_id3.htag_internal.htag_pool.ctag_pool.htag_print.ctag_print.htag_rva2.ctag_rva2.htag_save.ctag_save.htag_table.htext_file.ctext_file.htext_input_stream.ctext_input_stream.htimer.ctimer.htokenizer.ctokenizer.hupdate.cupdate.hupdate_archive.cupdate_archive.hupdate_container.cupdate_container.hupdate_db.cupdate_db.hupdate_internal.hupdate_io.cupdate_io.hupdate_queue.cupdate_queue.hupdate_remove.cupdate_remove.hupdate_song.cupdate_song.hupdate_walk.cupdate_walk.huri.curi.h
util
utils.cutils.hvolume.cvolume.h
win
zeroconf-avahi.czeroconf-bonjour.czeroconf-internal.hzeroconf.czeroconf.h
test
valgrind.suppressions

8
.gitignore vendored

@@ -34,11 +34,14 @@ missing
mkinstalldirs
mpd
mpd.exe
mpd.service
stamp-h1
tags
*~
.#*
.stgit*
src/dsd2pcm/dsd2pcm
doc/doxygen.conf
doc/protocol.html
doc/protocol
doc/user
@@ -59,3 +62,8 @@ test/dump_playlist
test/run_normalize
test/tmp
test/run_inotify
test/test_queue_priority
test/run_ntp_server
test/run_resolver
test/run_tcp_connect
test/test_pcm

21
INSTALL

@@ -13,7 +13,7 @@ Dependencies
gcc - http://gcc.gnu.org/
Any other C99 compliant compiler should also work.
GLib 2.12 - http://www.gtk.org/
GLib 2.16 - http://www.gtk.org/
General-purpose utility library.
@@ -84,11 +84,6 @@ For Ogg Vorbis support. You will need libogg and libvorbis.
FLAC - http://flac.sourceforge.net/
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. 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.
@@ -101,14 +96,14 @@ For Musepack support.
MikMod - http://mikmod.raphnet.net/
For MOD support. You will need libmikmod.
libavcodec, libavformat (ffmpeg) - http://ffmpeg.mplayerhq.hu/
libavcodec, libavformat (ffmpeg or libav) - http://ffmpeg.mplayerhq.hu/ http://libav.org/
Multi-codec library.
libsidplay2 - http://sidplay2.sourceforge.net/
For C64 SID support.
libfluidsynth - http://fluidsynth.resonance.org/
For MIDI support (DO NOT USE - use libwildmidi instead)
For MIDI support.
libwildmidi - http://wildmidi.sourceforge.net/
For MIDI support.
@@ -119,6 +114,9 @@ WAVE, AIFF, and many others.
libwavpack - http://www.wavpack.com/
For WavPack playback.
despotify - https://github.com/SimonKagstrom/despotify
For Spotify playback.
Optional Miscellaneous Dependencies
-----------------------------------
@@ -138,8 +136,11 @@ For playing MMS streams.
SQLite - http://www.sqlite.org/
For the sticker database.
libcue - http://libcue.sourceforge.net/
For CUE sheet support.
libcdio - http://www.gnu.org/software/libcdio/
For playing audio CDs.
libsystemd-daemon - http://freedesktop.org/wiki/Software/systemd/
For systemd activation.
pkg-config

File diff suppressed because it is too large Load Diff

213
NEWS

@@ -1,4 +1,202 @@
ver 0.16.1 (2010/01/09)
ver 0.17.2 (2012/09/30)
* protocol:
- fix crash in local file check
* decoder:
- fluidsynth: remove throttle (requires libfluidsynth 1.1)
- fluidsynth: stop playback at end of file
- fluidsynth: check MIDI file format while scanning
- fluidsynth: add sample rate setting
- wavpack: support all APEv2 tags
* output:
- httpd: use monotonic clock, avoid hiccups after system clock adjustment
- httpd: fix throttling bug after resuming playback
* playlist:
- cue: map "PERFORMER" to "artist" or "album artist"
* mapper: fix non-UTF8 music directory name
* mapper: fix potential crash in file permission check
* playlist: fix use-after-free bug
* playlist: fix memory leak
* state_file: save song priorities
* player: disable cross-fading in "single" mode
* update: fix unsafe readlink() usage
* configure.ac:
- don't auto-detect the vorbis encoder when Tremor is enabled
ver 0.17.1 (2012/07/31)
* protocol:
- require appropriate permissions for searchadd{,pl}
* tags:
- aiff: support the AIFC format
- ape: check for ID3 if no usable APE tag was found
* playlist:
- cue: support file types "MP3", "AIFF"
* output:
- fix noisy playback with conversion and software volume
ver 0.17 (2012/06/27)
* protocol:
- support client-to-client communication
- "update" and "rescan" need only "CONTROL" permission
- new command "seekcur" for simpler seeking within current song
- new command "config" dumps location of music directory
- add range parameter to command "load"
- print extra "playlist" object for embedded CUE sheets
- new commands "searchadd", "searchaddpl"
* input:
- cdio_paranoia: new input plugin to play audio CDs
- curl: enable CURLOPT_NETRC
- curl: non-blocking I/O
- soup: new input plugin based on libsoup
* tags:
- RVA2: support separate album/track replay gain
* decoder:
- mpg123: implement seeking
- ffmpeg: drop support for pre-0.5 ffmpeg
- ffmpeg: support WebM
- oggflac: delete this obsolete plugin
- dsdiff: new decoder plugin
* output:
- alsa: support DSD-over-USB (dCS suggested standard)
- httpd: support for streaming to a DLNA client
- openal: improve buffer cancellation
- osx: allow user to specify other audio devices
- osx: implement 32 bit playback
- shout: add possibility to set url
- roar: new output plugin for RoarAudio
- winmm: fail if wrong device specified instead of using default device
* mixer:
- alsa: listen for external volume changes
* playlist:
- allow references to songs outside the music directory
- new CUE parser, without libcue
- soundcloud: new plugin for accessing soundcloud.com
* state_file: add option "restore_paused"
* cue: show CUE track numbers
* allow port specification in "bind_to_address" settings
* support floating point samples
* systemd socket activation
* improve --version output
* WIN32: fix renaming of stored playlists with non-ASCII names
ver 0.16.8 (2012/04/04)
* fix for libsamplerate assertion failure
* decoder:
- vorbis (and others): fix seeking at startup
- ffmpeg: read the "year" tag
* encoder:
- vorbis: generate end-of-stream packet before tag
- vorbis: generate end-of-stream packet when playback ends
* output:
- jack: check for connection failure before starting playback
- jack: workaround for libjack1 crash bug
- osx: fix stuttering due to buffering bug
* fix endless loop in text file reader
* update: skip symlinks in path that is to be updated
ver 0.16.7 (2012/02/04)
* input:
- ffmpeg: support libavformat 0.7
* decoder:
- ffmpeg: support libavformat 0.8, libavcodec 0.9
- ffmpeg: support all MPD tags
* output:
- httpd: fix excessive buffering
- openal: force 16 bit playback, as 8 bit doesn't work
- osx: remove sleep call from render callback
- osx: clear render buffer when there's not enough data
* fix moving after current song
ver 0.16.6 (2011/12/01)
* decoder:
- fix assertion failure when resuming streams
- ffmpeg: work around bogus channel count
* encoder:
- flac, null, wave: fix buffer corruption bug
- wave: support packed 24 bit samples
* mapper: fix the bogus "not a directory" error message
* mapper: check "x" and "r" permissions on music directory
* log: print reason for failure
* event_pipe: fix WIN32 regression
* define WINVER in ./configure
* WIN32: autodetect filesystem encoding
ver 0.16.5 (2011/10/09)
* configure.ac
- disable assertions in the non-debugging build
- show solaris plugin result correctly
- add option --enable-solaris-output
* pcm_format: fix 32-to-24 bit conversion (the "silence" bug)
* input:
- rewind: reduce heap usage
* decoder:
- ffmpeg: higher precision timestamps
- ffmpeg: don't require key frame for seeking
- fix CUE track seeking
* output:
- openal: auto-fallback to mono if channel count is unsupported
* player:
- make seeking to CUE track more reliable
- the "seek" command works when MPD is stopped
- restore song position from state file (bug fix)
- fix crash that sometimes occurred when audio device fails on startup
- fix absolute path support in playlists
* WIN32: close sockets properly
* install systemd service file if systemd is available
ver 0.16.4 (2011/09/01)
* don't abort configure when avahi is not found
* auto-detect libmad without pkg-config
* fix memory leaks
* don't resume playback when seeking to another song while paused
* apply follow_inside_symlinks to absolute symlinks
* fix playback discontinuation after seeking
* input:
- curl: limit the receive buffer size
- curl: implement a hard-coded timeout of 10 seconds
* decoder:
- ffmpeg: workaround for semantic API change in recent ffmpeg versions
- flac: validate the sample rate when scanning the tag
- wavpack: obey all decoder commands, stop at CUE track border
* encoder:
- vorbis: don't send end-of-stream on flush
* output:
- alsa: fix SIGFPE when alsa announces a period size of 0
- httpd: don't warn on client disconnect
- osx: don't drain the buffer when closing
- pulse: fix deadlock when resuming the stream
- pulse: fix deadlock when the stream was suspended
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:
@@ -128,9 +326,20 @@ ver 0.16 (2010/12/11)
* make single mode 'sticky'
ver 0.15.16 (2010/??/??)
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)

@@ -16,7 +16,7 @@ if test -n "$AM_FORCE_VERSION"
then
AM_VERSIONS="$AM_FORCE_VERSION"
else
AM_VERSIONS='1.11 1.10'
AM_VERSIONS='1.11'
fi
if test -n "$AC_FORCE_VERSION"
then

@@ -1,11 +1,19 @@
AC_PREREQ(2.60)
AC_INIT(mpd, 0.16.1, musicpd-dev-team@lists.sourceforge.net)
AC_INIT(mpd, 0.17.2, musicpd-dev-team@lists.sourceforge.net)
VERSION_MAJOR=0
VERSION_MINOR=17
VERSION_REVISION=0
VERSION_EXTRA=0
AC_CONFIG_SRCDIR([src/main.c])
AM_INIT_AUTOMAKE([foreign 1.10 dist-bzip2 subdir-objects])
AM_CONFIG_HEADER(config.h)
AM_INIT_AUTOMAKE([foreign 1.11 dist-bzip2 subdir-objects])
AM_SILENT_RULES
AC_CONFIG_HEADERS(config.h)
AC_CONFIG_MACRO_DIR([m4])
AC_DEFINE(PROTOCOL_VERSION, "0.16.0", [The MPD protocol version])
AC_DEFINE(PROTOCOL_VERSION, "0.17.0", [The MPD protocol version])
dnl ---------------------------------------------------------------------------
@@ -29,20 +37,39 @@ if test x$CXX = xg++; then
HAVE_CXX=no
fi
fi
AM_CONDITIONAL(HAVE_CXX, test x$HAVE_CXX = xyes)
AC_PROG_INSTALL
AC_PROG_MAKE_SET
PKG_PROG_PKG_CONFIG
AC_ARG_WITH([systemdsystemunitdir],
AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files]),
[], [with_systemdsystemunitdir=no])
if test "x$with_systemdsystemunitdir" = xyes; then
AC_MSG_CHECKING(for systemd)
with_systemdsystemunitdir=$($PKG_CONFIG --variable=systemdsystemunitdir systemd)
if test -z "$with_systemdsystemunitdir"; then
AC_MSG_ERROR([Failed to detect systemd])
fi
AC_MSG_RESULT([$with_systemdsystemunitdir])
fi
if test "x$with_systemdsystemunitdir" != xno; then
AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])
fi
AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdsystemunitdir" -a "x$with_systemdsystemunitdir" != xno ])
dnl ---------------------------------------------------------------------------
dnl Declare Variables
dnl ---------------------------------------------------------------------------
AC_SUBST(AM_CPPFLAGS,"")
AC_SUBST(AM_CFLAGS,"")
AC_SUBST(AM_CXXFLAGS,"")
AC_SUBST(MPD_LIBS)
AC_SUBST(MPD_CFLAGS)
MPD_LIBS=""
MPD_CFLAGS=""
## Used for the windows resource file
AC_SUBST(VERSION_MAJOR)
AC_SUBST(VERSION_MINOR)
AC_SUBST(VERSION_REVISION)
AC_SUBST(VERSION_EXTRA)
dnl ---------------------------------------------------------------------------
dnl OS Specific Defaults
@@ -51,9 +78,16 @@ AC_CANONICAL_HOST
case "$host_os" in
mingw32* | windows*)
MPD_LIBS="$MPD_LIBS -lws2_32"
AC_CONFIG_FILES([
src/win/mpd_win32_rc.rc
])
AC_CHECK_TOOL(WINDRES, windres)
AM_CPPFLAGS="$AM_CPPFLAGS -DWINVER=0x0501"
LIBS="$LIBS -lws2_32"
HAVE_WINDOWS=1
;;
esac
AM_CONDITIONAL([HAVE_WINDOWS], [test x$HAVE_WINDOWS = x1])
if test -z "$prefix" || test "x$prefix" = xNONE; then
local_lib=
@@ -85,7 +119,7 @@ if test -z "$prefix" || test "x$prefix" = xNONE; then
done
for d in $local_include; do
if test -d "$d"; then
CFLAGS="$CFLAGS -I$d"
CPPFLAGS="$CPPFLAGS -I$d"
break
fi
done
@@ -94,22 +128,18 @@ fi
dnl ---------------------------------------------------------------------------
dnl Header/Library Checks
dnl ---------------------------------------------------------------------------
AC_CHECK_FUNCS(daemon fork syslog)
if test $ac_cv_func_syslog = no; then
# syslog is not in the default libraries. See if it's in some other.
for lib in bsd socket inet; do
AC_CHECK_LIB($lib, syslog,
[AC_DEFINE(HAVE_SYSLOG)
LIBS="$LIBS -l$lib"; break])
done
fi
AC_CHECK_FUNCS(daemon fork)
AC_CHECK_LIB(socket,socket,MPD_LIBS="$MPD_LIBS -lsocket",)
AC_CHECK_LIB(nsl,gethostbyname,MPD_LIBS="$MPD_LIBS -lnsl",)
AC_SEARCH_LIBS([syslog], [bsd socket inet],
[AC_DEFINE(HAVE_SYSLOG, 1, [Define if syslog() is available])])
AC_SEARCH_LIBS([socket], [socket])
AC_SEARCH_LIBS([gethostbyname], [nsl])
AC_CHECK_FUNCS(pipe2 accept4)
AC_CHECK_LIB(m,exp,MPD_LIBS="$MPD_LIBS -lm",)
AC_SEARCH_LIBS([exp], [m],,
[AC_MSG_ERROR([exp() not found])])
AC_CHECK_HEADERS(locale.h)
AC_CHECK_HEADERS(valgrind/memcheck.h)
@@ -121,6 +151,11 @@ AC_ARG_ENABLE(alsa,
AS_HELP_STRING([--enable-alsa], [enable ALSA support]),,
[enable_alsa=auto])
AC_ARG_ENABLE(roar,
AS_HELP_STRING([--enable-roar],
[enable support for RoarAudio]),,
[enable_roar=auto])
AC_ARG_ENABLE(ao,
AS_HELP_STRING([--enable-ao],
[enable support for libao]),,
@@ -136,16 +171,21 @@ AC_ARG_ENABLE(bzip2,
[enable bzip2 archive support (default: disabled)]),,
enable_bzip2=no)
AC_ARG_ENABLE(cue,
AS_HELP_STRING([--enable-cue],
[enable support for libcue support]),,
enable_cue=auto)
AC_ARG_ENABLE(cdio-paranoia,
AS_HELP_STRING([--enable-cdio-paranoia],
[enable support for audio CD support]),,
enable_cdio_paranoia=auto)
AC_ARG_ENABLE(curl,
AS_HELP_STRING([--enable-curl],
[enable support for libcurl HTTP streaming (default: auto)]),,
[enable_curl=auto])
AC_ARG_ENABLE(soup,
AS_HELP_STRING([--enable-soup],
[enable support for libsoup HTTP streaming (default: auto)]),,
[enable_soup=auto])
AC_ARG_ENABLE(debug,
AS_HELP_STRING([--enable-debug],
[enable debugging (default: disabled)]),,
@@ -171,34 +211,29 @@ AC_ARG_ENABLE(fifo,
enable_fifo=yes)
AC_ARG_ENABLE(flac,
AS_HELP_STRING([--disable-flac],
[disable flac support (default: enable)]),,
enable_flac=yes)
AS_HELP_STRING([--enable-flac],
[enable FLAC decoder]),,
enable_flac=auto)
AC_ARG_ENABLE(fluidsynth,
AS_HELP_STRING([--enable-fluidsynth],
[enable MIDI support via fluidsynth (default: disable)]),,
enable_fluidsynth=no)
[enable MIDI support via fluidsynth (default: auto)]),,
enable_fluidsynth=auto)
AC_ARG_ENABLE(gme,
AS_HELP_STRING([--enable-gme],
[enable Blargg's game music emulator plugin]),,
enable_gme=auto)
AC_ARG_ENABLE(gprof,
AS_HELP_STRING([--enable-gprof],
[enable profiling via gprof (default: disabled)]),,
enable_gprof=no)
AC_ARG_ENABLE(httpd-output,
AS_HELP_STRING([--enable-httpd-output],
[enables the HTTP server output]),,
[enable_httpd_output=auto])
AC_ARG_ENABLE(id3,
AS_HELP_STRING([--disable-id3],
[disable id3 support (default: enable)]),,
enable_id3=yes)
AS_HELP_STRING([--enable-id3],
[enable id3 support]),,
enable_id3=auto)
AC_ARG_ENABLE(inotify,
AS_HELP_STRING([--disable-inotify],
@@ -227,6 +262,16 @@ AC_ARG_ENABLE(lastfm,
[enable support for last.fm radio (default: disable)]),,
[enable_lastfm=no])
AC_ARG_ENABLE(despotify,
AS_HELP_STRING([--enable-despotify],
[enable support for despotify (default: disable)]),,
[enable_despotify=no])
AC_ARG_ENABLE(soundcloud,
AS_HELP_STRING([--enable-soundcloud],
[enable support for soundcloud.com]),,
[enable_soundcloud=auto])
AC_ARG_ENABLE(lame-encoder,
AS_HELP_STRING([--enable-lame-encoder],
[enable the LAME mp3 encoder]),,
@@ -276,11 +321,6 @@ AC_ARG_ENABLE(mvp,
[enable support for Hauppauge Media MVP (default: disable)]),,
enable_mvp=no)
AC_ARG_ENABLE(oggflac,
AS_HELP_STRING([--disable-oggflac],
[disable OggFLAC support (default: enable)]),,
enable_oggflac=yes)
AC_ARG_ENABLE(openal,
AS_HELP_STRING([--enable-openal],
[enable OpenAL support (default: disable)]),,
@@ -322,11 +362,21 @@ AC_ARG_ENABLE(sndfile,
[enable sndfile support]),,
enable_sndfile=auto)
AC_ARG_ENABLE(solaris_output,
AS_HELP_STRING([--enable-solaris-output],
[enables the Solaris /dev/audio output]),,
[enable_solaris_output=auto])
AC_ARG_ENABLE(sqlite,
AS_HELP_STRING([--enable-sqlite],
[enable support for the SQLite database]),,
[enable_sqlite=auto])
AC_ARG_ENABLE(systemd-daemon,
AS_HELP_STRING([--enable-systemd-daemon],
[use the systemd daemon library (default=auto)]),,
[enable_systemd_daemon=auto])
AC_ARG_ENABLE(tcp,
AS_HELP_STRING([--disable-tcp],
[disable support for clients connecting via TCP (default: enable)]),,
@@ -353,9 +403,9 @@ AC_ARG_ENABLE(un,
[enable_un=yes])
AC_ARG_ENABLE(vorbis,
AS_HELP_STRING([--disable-vorbis],
[disable Ogg Vorbis support (default: enable)]),,
enable_vorbis=yes)
AS_HELP_STRING([--enable-vorbis],
[enable Ogg Vorbis decoder]),,
enable_vorbis=auto)
AC_ARG_ENABLE(vorbis-encoder,
AS_HELP_STRING([--enable-vorbis-encoder],
@@ -406,8 +456,13 @@ AC_ARG_WITH(tremor-includes,
dnl ---------------------------------------------------------------------------
dnl Mandatory Libraries
dnl ---------------------------------------------------------------------------
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.12 gthread-2.0],,
[AC_MSG_ERROR([GLib 2.12 is required])])
PKG_CHECK_MODULES([GLIB], [glib-2.0 >= 2.16 gthread-2.0],,
[AC_MSG_ERROR([GLib 2.16 is required])])
if test x$GCC = xyes; then
# suppress warnings in the GLib headers
GLIB_CFLAGS=`echo $GLIB_CFLAGS |sed -e 's,-I/,-isystem /,g'`
fi
dnl ---------------------------------------------------------------------------
dnl Protocol Options
@@ -423,7 +478,11 @@ if test x$enable_ipv6 = xyes; then
AC_EGREP_CPP([AP_maGiC_VALUE],
[
#include <sys/types.h>
#ifdef WIN32
#include <winsock2.h>
#else
#include <sys/socket.h>
#endif
#include <netdb.h>
#ifdef PF_INET6
#ifdef AF_INET6
@@ -460,6 +519,13 @@ if
AC_MSG_ERROR([No client interfaces configured!])
fi
MPD_AUTO_PKG(systemd_daemon, SYSTEMD_DAEMON, libsystemd-daemon,
[systemd activation], [libsystemd-daemon not found])
AM_CONDITIONAL(ENABLE_SYSTEMD_DAEMON, test x$enable_systemd_daemon = xyes)
if test x$enable_systemd_daemon = xyes; then
AC_DEFINE([ENABLE_SYSTEMD_DAEMON], 1, [Define to use the systemd daemon library])
fi
dnl ---------------------------------------------------------------------------
dnl LIBC Features
dnl ---------------------------------------------------------------------------
@@ -499,24 +565,9 @@ dnl ---------------------------------------------------------------------------
dnl Metadata Plugins
dnl ---------------------------------------------------------------------------
dnl ---------------------------------- libcue ---------------------------------
MPD_AUTO_PKG(cue, CUE, [libcue],
[libcue parsing library], [libcue not found])
if test x$enable_cue = xyes; then
AC_DEFINE([HAVE_CUE], 1,
[Define to enable libcue support])
fi
AM_CONDITIONAL(HAVE_CUE, test x$enable_cue = xyes)
dnl -------------------------------- libid3tag --------------------------------
if test x$enable_id3 = xyes; then
PKG_CHECK_MODULES([ID3TAG], [id3tag],,
AC_CHECK_LIB(id3tag, id3_file_open,
[ID3TAG_LIBS="-lid3tag -lz" ID3TAG_CFLAGS=""],
enable_id3=no))
fi
MPD_AUTO_PKG_LIB(id3, ID3TAG, id3tag, id3tag, id3_file_open, [-lid3tag -lz], [],
[id3tag], [libid3tag not found])
if test x$enable_id3 = xyes; then
AC_DEFINE(HAVE_ID3TAG, 1, [Define to use id3tag])
fi
@@ -530,36 +581,38 @@ dnl ---------------------------------------------------------------------------
dnl --------------------------------- zeroconf --------------------------------
case $with_zeroconf in
no|avahi|bonjour)
no|bonjour)
enable_avahi=no
;;
avahi)
enable_avahi=yes
;;
*)
with_zeroconf=auto
enable_avahi=auto
;;
esac
MPD_AUTO_PKG(avahi, AVAHI, [avahi-client avahi-glib],
[avahi client library], [avahi client+glib not found])
if test x$enable_avahi = xyes; then
AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])
with_zeroconf=avahi
fi
AM_CONDITIONAL(HAVE_AVAHI, test x$enable_avahi = xyes)
enable_bounjour=no
if test x$with_zeroconf != xno; then
if test x$with_zeroconf = xavahi || test x$with_zeroconf = xauto; then
PKG_CHECK_MODULES([AVAHI], [avahi-client avahi-glib],
[found_avahi=1;AC_DEFINE([HAVE_AVAHI], 1, [Define to enable Avahi Zeroconf support])]
MPD_LIBS="$MPD_LIBS $AVAHI_LIBS" MPD_CFLAGS="$MPD_CFLAGS $AVAHI_CFLAGS",
[found_avahi=0])
fi
if test x$found_avahi = x1; then
with_zeroconf=avahi
elif test x$with_zeroconf = xavahi; then
AC_MSG_ERROR([Avahi support requested but not found])
fi
if test x$with_zeroconf = xbonjour || test x$with_zeroconf = xauto; then
AC_CHECK_HEADER(dns_sd.h,
[found_bonjour=1;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])],
[found_bonjour=0])
AC_CHECK_LIB(dns_sd, DNSServiceRegister,
MPD_LIBS="$MPD_LIBS -ldns_sd")
[enable_bonjour=yes;AC_DEFINE([HAVE_BONJOUR], 1, [Define to enable Bonjour Zeroconf support])])
AC_CHECK_LIB([dns_sd], [DNSServiceRegister])
fi
if test x$found_bonjour = x1; then
if test x$enable_bonjour = xyes; then
with_zeroconf=bonjour
elif test x$with_zeroconf = xbonjour; then
AC_MSG_ERROR([Bonjour support requested but not found])
@@ -574,7 +627,6 @@ if test x$with_zeroconf != xno; then
fi
AM_CONDITIONAL(HAVE_ZEROCONF, test x$with_zeroconf != xno)
AM_CONDITIONAL(HAVE_AVAHI, test x$with_zeroconf = xavahi)
AM_CONDITIONAL(HAVE_BONJOUR, test x$with_zeroconf = xbonjour)
dnl ---------------------------------------------------------------------------
@@ -624,6 +676,14 @@ if test x$enable_curl = xyes; then
fi
AM_CONDITIONAL(ENABLE_CURL, test x$enable_curl = xyes)
dnl ----------------------------------- SOUP ----------------------------------
MPD_AUTO_PKG(soup, SOUP, [libsoup-2.4],
[libsoup HTTP streaming], [libsoup not found])
if test x$enable_soup = xyes; then
AC_DEFINE(ENABLE_SOUP, 1, [Define when libsoup is used for HTTP streaming])
fi
AM_CONDITIONAL(ENABLE_SOUP, test x$enable_soup = xyes)
dnl --------------------------------- Last.FM ---------------------------------
if test x$enable_lastfm = xyes; then
if test x$enable_curl != xyes; then
@@ -634,10 +694,38 @@ if test x$enable_lastfm = xyes; then
fi
AM_CONDITIONAL(ENABLE_LASTFM, test x$enable_lastfm = xyes)
dnl ---------------------------------- libogg ---------------------------------
if test x$with_tremor == xno || test -z $with_tremor; then
PKG_CHECK_MODULES(OGG, [ogg], enable_ogg=yes, enable_ogg=no)
dnl --------------------------------- Despotify ---------------------------------
MPD_AUTO_PKG(despotify, DESPOTIFY, [despotify],
[Despotify support], [despotify not found])
if test x$enable_despotify = xyes; then
AC_DEFINE(ENABLE_DESPOTIFY, 1, [Define when despotify is enabled])
fi
AM_CONDITIONAL(ENABLE_DESPOTIFY, test x$enable_despotify = xyes)
dnl --------------------------------- Soundcloud ------------------------------
if test x$enable_soundcloud != xno; then
PKG_CHECK_MODULES([YAJL], [yajl >= 2.0],
[found_soundcloud=yes],
AC_CHECK_LIB([yajl], [yajl_alloc],
[found_soundcloud=yes YAJL_CFLAGS=-DHAVE_YAJL1 YAJL_LIBS=-lyajl],
[found_soundcloud=no]))
fi
MPD_AUTO_RESULT([soundcloud], [soundcloud.com support], [libyajl not found])
if test x$enable_soundcloud = xyes; then
AC_DEFINE(ENABLE_SOUNDCLOUD, 1, [Define when soundcloud is enabled])
fi
AM_CONDITIONAL(ENABLE_SOUNDCLOUD, test x$enable_soundcloud = xyes)
AC_SUBST(YAJL_LIBS)
dnl ---------------------------------- cdio ---------------------------------
MPD_AUTO_PKG(cdio_paranoia, CDIO_PARANOIA, [libcdio_paranoia],
[libcdio_paranoia audio CD library], [libcdio_paranoia not found])
if test x$enable_cdio_paranoia = xyes; then
AC_DEFINE([ENABLE_CDIO_PARANOIA], 1,
[Define to enable libcdio_paranoia support])
fi
AM_CONDITIONAL(ENABLE_CDIO_PARANOIA, test x$enable_cdio_paranoia = xyes)
dnl ---------------------------------- libmms ---------------------------------
MPD_AUTO_PKG(mms, MMS, [libmms >= 0.4],
@@ -670,9 +758,10 @@ AM_CONDITIONAL(ENABLE_ISO9660_TEST, test x$MKISOFS != xno)
dnl ---------------------------------- libbz2 ---------------------------------
if test x$enable_bzip2 = xyes; then
AC_CHECK_LIB(bz2, BZ2_bzDecompressInit,
[MPD_LIBS="$MPD_LIBS -lbz2"],
[BZ2_LIBS="-lbz2"],
[AC_MSG_ERROR([libbz2 not found])])
fi
AC_SUBST(BZ2_LIBS)
AM_CONDITIONAL(HAVE_BZ2, test x$enable_bzip2 = xyes)
if test x$enable_bzip2 = xyes; then
@@ -732,20 +821,9 @@ AM_CONDITIONAL(HAVE_FAAD, test x$enable_aac = xyes)
AM_CONDITIONAL(HAVE_MP4, test x$enable_mp4 = xyes)
dnl ---------------------------------- ffmpeg ---------------------------------
MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat >= 52 libavcodec >= 51 libavutil >= 49],
MPD_AUTO_PKG(ffmpeg, FFMPEG, [libavformat >= 52.31 libavcodec >= 52.20 libavutil >= 49.15],
[ffmpeg decoder library], [libavformat+libavcodec+libavutil not found])
if test x$enable_ffmpeg = xyes; then
# prior to ffmpeg svn12865, you had to specify include files
# without path prefix
old_CPPCFLAGS=$CPPFLAGS
CPPFLAGS="$CPPFLAGS $FFMPEG_CFLAGS"
AC_CHECK_HEADER(libavcodec/avcodec.h,,
AC_DEFINE(OLD_FFMPEG_INCLUDES, 1,
[Define if avcodec.h instead of libavcodec/avcodec.h should be included]))
CPPCFLAGS=$old_CPPFLAGS
fi
if test x$enable_ffmpeg = xyes; then
AC_DEFINE(HAVE_FFMPEG, 1, [Define for FFMPEG support])
fi
@@ -753,31 +831,12 @@ fi
AM_CONDITIONAL(HAVE_FFMPEG, test x$enable_ffmpeg = xyes)
dnl ----------------------------------- FLAC ----------------------------------
MPD_AUTO_PKG(flac, FLAC, [flac >= 1.1],
[FLAC decoder], [libFLAC not found])
if test x$enable_flac = xyes; then
PKG_CHECK_MODULES(FLAC, [flac >= 1.1],
AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support]),
enable_flac=no)
oldcflags="$CFLAGS"
oldlibs="$LIBS"
CFLAGS="$CFLAGS $FLAC_CFLAGS"
LIBS="$LIBS $FLAC_LIBS"
if test x$enable_flac = xyes && test x$enable_oggflac = xyes; then
AC_CHECK_DECL(FLAC_API_SUPPORTS_OGG_FLAC,
[enable_oggflac=flac], [],
[#include <FLAC/export.h>])
fi
CFLAGS="$oldcflags"
LIBS="$oldlibs"
if test x$enable_oggflac = xflac; then
if test x$enable_ogg = xyes; then
FLAC_LIBS="${FLAC_LIBS} -logg"
else
enable_oggflac=yes
AC_MSG_WARN("FLAC has the ogg API built in, but couldn't find ogg. Disabling oggflac.")
fi
fi
AC_DEFINE(HAVE_FLAC, 1, [Define for FLAC support])
fi
AM_CONDITIONAL(HAVE_FLAC, test x$enable_flac = xyes)
@@ -786,7 +845,7 @@ enable_flac_encoder=$enable_flac
dnl -------------------------------- FluidSynth -------------------------------
if test x$enable_fluidsynth = xyes; then
PKG_CHECK_MODULES(FLUIDSYNTH, [fluidsynth],
PKG_CHECK_MODULES(FLUIDSYNTH, [fluidsynth >= 1.1],
AC_DEFINE(ENABLE_FLUIDSYNTH, 1, [Define for fluidsynth support]),
enable_fluidsynth=no)
fi
@@ -802,7 +861,8 @@ if test x$enable_gme = xyes; then
fi
dnl ---------------------------------- libmad ---------------------------------
MPD_AUTO_PKG(mad, MAD, [mad],
MPD_AUTO_PKG_LIB(mad, MAD, [mad],
mad, mad_stream_init, [-lmad], [],
[libmad MP3 decoder plugin], [libmad not found])
if test x$enable_mad = xyes; then
AC_DEFINE(HAVE_MAD, 1, [Define to use libmad])
@@ -862,52 +922,32 @@ AM_CONDITIONAL(ENABLE_SNDFILE, test x$enable_sndfile = xyes)
dnl --------------------------------- musepack --------------------------------
if test x$enable_mpc = xyes; then
if test "x$mpcdec_libraries" != "x" ; then
MPCDEC_LIBS="-L$mpcdec_libraries"
elif test "x$mpcdec_prefix" != "x" ; then
MPCDEC_LIBS="-L$mpcdec_prefix/lib"
fi
MPCDEC_LIBS="$MPCDEC_LIBS -lmpcdec"
if test "x$mpcdec_includes" != "x" ; then
MPCDEC_CFLAGS="-I$mpcdec_includes"
elif test "x$mpcdec_prefix" != "x" ; then
MPCDEC_CFLAGS="-I$mpcdec_prefix/include"
fi
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $MPD_CFLAGS $MPCDEC_CFLAGS -I."
LIBS="$LIBS $MPD_LIBS $MPCDEC_LIBS"
CPPFLAGS=$CFLAGS
AC_CHECK_HEADER(mpc/mpcdec.h,
old_mpcdec=no,
[AC_CHECK_HEADER(mpcdec/mpcdec.h,
old_mpcdec=yes,
enable_mpc=no)])
if test x$enable_mpc = xyes; then
AC_CHECK_LIB(mpcdec,main,
[MPD_LIBS="$MPD_LIBS $MPCDEC_LIBS";
MPD_CFLAGS="$MPD_CFLAGS $MPCDEC_CFLAGS";],
AC_CHECK_LIB(mpcdec,main,
MPCDEC_LIBS="$MPCDEC_LIBS -lmpcdec",
enable_mpc=no)
fi
if test x$enable_mpc = xyes; then
AC_DEFINE(HAVE_MPCDEC,1,
[Define to use libmpcdec for MPC decoding])
if test x$old_mpcdec = xyes; then
AC_DEFINE(MPC_IS_OLD_API, 1,
[Define if an old pre-SV8 libmpcdec is used])
fi
else
AC_MSG_WARN([mpcdec lib needed for MPC support -- disabling MPC support])
fi
CFLAGS=$oldcflags
LIBS=$oldlibs
CPPFLAGS=$oldcppflags
if test x$enable_mpc = xyes; then
AC_CHECK_HEADER([mpc/mpcdec.h],
[AC_DEFINE(HAVE_MPCDEC,1,
[Define to use libmpcdec for MPC decoding])],
[AC_CHECK_HEADER(mpcdec/mpcdec.h,
[AC_DEFINE(MPC_IS_OLD_API, 1,
[Define if an old pre-SV8 libmpcdec is used])]
)]
)
else
AC_MSG_WARN([mpcdec lib needed for MPC support -- disabling MPC support])
fi
fi
AC_SUBST(MPCDEC_LIBS)
AC_SUBST(MPCDEC_CFLAGS)
AM_CONDITIONAL(HAVE_MPCDEC, test x$enable_mpc = xyes)
dnl -------------------------------- Ogg Tremor -------------------------------
@@ -934,53 +974,45 @@ 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)
AC_SUBST(TREMOR_LIBS)
dnl --------------------------------- OggFLAC ---------------------------------
dnl OggFLAC must go after Ogg Tremor
if test x$enable_tremor = xyes && test x$enable_oggflac = xyes; then
AC_MSG_WARN([disabling OggFLAC support because it is incompatible with tremor])
enable_oggflac=no
fi
if test x$enable_oggflac = xyes; then
AC_CHECK_HEADER([OggFLAC/stream_decoder.h],, enable_oggflac=no)
fi
if test x$enable_oggflac = xyes; then
AC_DEFINE(HAVE_OGGFLAC,1,[Define for OggFLAC support])
MPD_LIBS="$MPD_LIBS -lOggFLAC -lFLAC -lm"
fi
AM_CONDITIONAL(HAVE_OGGFLAC, test x$enable_oggflac = xyes)
dnl -------------------------------- Ogg Vorbis -------------------------------
if test x$enable_vorbis = xyes; then
if test x$enable_tremor = xyes; then
if test x$enable_tremor = xyes; then
if test x$enable_vorbis = xyes; then
AC_MSG_WARN(["OggTremor detected, could not enable Vorbis."])
enable_vorbis=no
elif test x$enable_ogg = xyes; then
PKG_CHECK_MODULES(VORBIS, [vorbis vorbisfile],
AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support]),
enable_vorbis=no)
else
AC_MSG_WARN(["Ogg not detected, could not enable Vorbis."])
enable_vorbis=no
fi
enable_vorbis=no
if test x$enable_vorbis_encoder = xauto; then
AC_MSG_WARN([OggTremor detected, disabling the Vorbis encoder plugin.])
enable_vorbis_encoder=no
fi
fi
AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes)
MPD_AUTO_PKG(vorbis, VORBIS, [vorbis vorbisfile ogg],
[Ogg Vorbis decoder], [libvorbis not found])
if test x$enable_vorbis = xyes; then
AC_DEFINE(ENABLE_VORBIS_DECODER, 1, [Define for Ogg Vorbis support])
fi
AM_CONDITIONAL(ENABLE_VORBIS_DECODER, test x$enable_vorbis = xyes || test x$enable_tremor = xyes)
dnl --------------------------------- sidplay ---------------------------------
found_sidplay=$HAVE_CXX
@@ -989,19 +1021,18 @@ MPD_AUTO_PRE(sidplay, [sidplay decoder plugin], [No C++ compiler found])
if test x$enable_sidplay != xno; then
# we're not using pkg-config here
# because libsidplay2's .pc file requires libtool
AC_HAVE_LIBRARY(sidplay2, [found_sidplay=yes], [found_sidplay=no])
AC_CHECK_LIB([sidplay2],[main],[found_sidplay=yes],[found_sidplay=no],[])
MPD_AUTO_PRE(sidplay, [sidplay decoder plugin],
[libsidplay2 not found])
fi
if test x$enable_sidplay != xno; then
# can't use AC_HAVE_LIBRARY here, because the dash in the
# library name triggers an autoconf bug
AC_CHECK_LIB(resid-builder, main,
AC_CHECK_LIB([resid-builder], [main],
[found_sidplay=yes], [found_sidplay=no])
if test x$found_sidplay = xyes; then
AC_HAVE_LIBRARY(sidutils,, [found_sidplay=no])
AC_CHECK_LIB([sidutils],[main],[],[found_sidplay=no],[])
fi
MPD_AUTO_RESULT(sidplay, [sidplay decoder plugin],
@@ -1064,7 +1095,6 @@ if
test x$enable_mp4 = xno &&
test x$enable_mpc = xno &&
test x$enable_mpg123 = xno &&
test x$enable_oggflac = xno &&
test x$enable_sidplay = xno &&
test x$enable_tremor = xno &&
test x$enable_vorbis = xno &&
@@ -1075,10 +1105,10 @@ 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_flac = xyes)
AM_CONDITIONAL(HAVE_FLAC_COMMON,
test x$enable_flac = xyes || test x$enable_oggflac = xyes)
test x$enable_flac = xyes)
dnl ---------------------------------------------------------------------------
dnl Encoders for Streaming Audio Output Plugins
@@ -1201,6 +1231,16 @@ fi
AM_CONDITIONAL(HAVE_ALSA, test x$enable_alsa = xyes)
dnl ----------------------------------- ROAR ----------------------------------
MPD_AUTO_PKG(roar, ROAR, [libroar >= 0.4.0],
[ROAR output plugin], [libroar not found])
if test x$enable_roar = xyes; then
AC_DEFINE(HAVE_ROAR, 1, [Define to enable ROAR support])
fi
AM_CONDITIONAL(HAVE_ROAR, test x$enable_roar = xyes)
dnl ----------------------------------- FFADO ---------------------------------
MPD_AUTO_PKG(ffado, FFADO, [libffado],
@@ -1311,7 +1351,7 @@ enable_osx=no
case "$host_os" in
darwin*)
AC_DEFINE(HAVE_OSX, 1, [Define for compiling OS X support])
MPD_LIBS="$MPD_LIBS -framework AudioUnit -framework CoreServices"
LIBS="$LIBS -framework AudioUnit -framework CoreAudio -framework CoreServices"
enable_osx=yes ;;
esac
@@ -1369,16 +1409,22 @@ fi
AM_CONDITIONAL(HAVE_SHOUT, test x$enable_shout = xyes)
dnl --------------------------------- Solaris ---------------------------------
case "$host_os" in
if test x$enable_solaris_output = xauto; then
case "$host_os" in
solaris*)
AC_DEFINE(ENABLE_SOLARIS_OUTPUT, 1, [Define to enable Solaris /dev/audio support])
enable_solaris_output=yes
;;
*)
enable_solaris_output=no
;;
esac
esac
fi
if test x$enable_solaris_output = xyes; then
AC_DEFINE(ENABLE_SOLARIS_OUTPUT, 1, [Define to enable Solaris /dev/audio support])
fi
AM_CONDITIONAL(ENABLE_SOLARIS_OUTPUT, test x$enable_solaris_output = xyes)
@@ -1388,7 +1434,7 @@ case "$host_os" in
mingw32* | windows*)
AC_DEFINE(ENABLE_WINMM_OUTPUT, 1, [Define to enable WinMM support])
enable_winmm_output=yes
MPD_LIBS="$MPD_LIBS -lwinmm"
LIBS="$LIBS -lwinmm"
;;
*)
@@ -1401,6 +1447,7 @@ AM_CONDITIONAL(ENABLE_WINMM_OUTPUT, test x$enable_winmm_output = xyes)
dnl --------------------- Post Audio Output Plugins Tests ---------------------
if
test x$enable_alsa = xno &&
test x$enable_roar = xno &&
test x$enable_ao = xno &&
test x$enable_ffado = xno &&
test x$enable_fifo = xno &&
@@ -1450,35 +1497,28 @@ dnl CFLAGS
dnl ---------------------------------------------------------------------------
dnl ---------------------------------- debug ----------------------------------
#if test "x$enable_debug" = xno; then
# don't set NDEBUG for now, until MPD is stable
#AM_CFLAGS="$AM_CFLAGS -DNDEBUG"
#fi
if test "x$enable_debug" = xno; then
AM_CPPFLAGS="$AM_CPPFLAGS -DNDEBUG"
fi
dnl ----------------------------------- GCC -----------------------------------
if test x$GCC = xyes
then
MPD_CHECK_FLAG([-Wall])
MPD_CHECK_FLAG([-Wextra])
MPD_CHECK_FLAG([-Wno-deprecated-declarations])
MPD_CHECK_FLAG([-Wmissing-prototypes])
MPD_CHECK_FLAG([-Wshadow])
MPD_CHECK_FLAG([-Wpointer-arith])
MPD_CHECK_FLAG([-Wstrict-prototypes])
MPD_CHECK_FLAG([-Wcast-qual])
MPD_CHECK_FLAG([-Wwrite-strings])
MPD_CHECK_FLAG([-pedantic])
fi
dnl ------------------------------ gprof profiler -----------------------------
if test "x$enable_gprof" = xyes; then
MPD_CFLAGS="$MPD_CFLAGS -pg"
MPD_LIBS="$MPD_LIBS -pg"
AX_APPEND_COMPILE_FLAGS([-Wall])
AX_APPEND_COMPILE_FLAGS([-Wextra])
AX_APPEND_COMPILE_FLAGS([-Wmissing-prototypes])
AX_APPEND_COMPILE_FLAGS([-Wshadow])
AX_APPEND_COMPILE_FLAGS([-Wpointer-arith])
AX_APPEND_COMPILE_FLAGS([-Wstrict-prototypes])
AX_APPEND_COMPILE_FLAGS([-Wcast-qual])
AX_APPEND_COMPILE_FLAGS([-Wwrite-strings])
AX_APPEND_COMPILE_FLAGS([-pedantic])
fi
dnl ---------------------------- warnings as errors ---------------------------
if test "x$enable_werror" = xyes; then
AM_CFLAGS="$AM_CFLAGS -Werror -pedantic-errors"
AM_CXXFLAGS="$AM_CXXFLAGS -Werror"
fi
dnl ---------------------------------------------------------------------------
@@ -1518,7 +1558,6 @@ results(mad, [MAD])
results(mpg123, [MPG123])
results(mp4, [MP4])
results(mpc, [Musepack])
results(oggflac, [OggFLAC], flac)
printf '\n\t'
results(tremor, [OggTremor])
results(vorbis, [OggVorbis])
@@ -1532,7 +1571,6 @@ results(inotify, [inotify])
results(sqlite, [SQLite])
printf '\nMetadata support:\n\t'
results(cue,[cue])
results(id3,[ID3])
printf '\nPlayback support:\n\t'
@@ -1542,17 +1580,18 @@ results(fifo,FIFO)
results(recorder_output,[File Recorder])
results(httpd_output,[HTTP Daemon])
results(jack,[JACK])
results(ao,[libao])
results(oss,[OSS])
printf '\n\t'
results(ao,[libao])
results(mvp, [Media MVP])
results(oss,[OSS])
results(openal,[OpenAL])
results(osx, [OS X])
results(pipe_output, [Pipeline])
results(pulse, [PulseAudio])
results(mvp, [Media MVP])
results(shout, [SHOUTcast])
printf '\n\t'
results(solaris, [Solaris])
results(pulse, [PulseAudio])
results(roar,[ROAR])
results(shout, [SHOUTcast])
results(solaris_output, [Solaris])
results(winmm_output, [WinMM])
if
@@ -1568,9 +1607,14 @@ if
fi
printf '\nStreaming support:\n\t'
results(cdio_paranoia, [CDIO_PARANOIA])
results(curl,[CURL])
results(despotify,[Despotify])
results(lastfm,[Last.FM])
results(soundcloud,[Soundcloud])
printf '\n\t'
results(mms,[MMS])
results(soup, [SOUP])
printf '\n\n##########################################\n\n'
@@ -1579,6 +1623,9 @@ echo 'Generating files needed for compilation'
dnl ---------------------------------------------------------------------------
dnl Generate files
dnl ---------------------------------------------------------------------------
AC_OUTPUT(Makefile)
AC_CONFIG_FILES(Makefile)
AC_CONFIG_FILES(doc/doxygen.conf)
AC_CONFIG_FILES(mpd.service)
AC_OUTPUT
echo 'MPD is ready for compilation, type "make" to begin.'

@@ -57,7 +57,7 @@
Some example code:
</para>
<programlisting lang="C">static inline bool
<programlisting lang="C">static inline int
foo(const char *abc, int xyz)
{
if (abc == NULL) {

@@ -31,7 +31,7 @@ PROJECT_NAME = MPD
# This could be handy for archiving the generated documentation or
# if some version control system is used.
PROJECT_NUMBER =
PROJECT_NUMBER = @VERSION@
# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
# base path where the generated documentation will be put.
@@ -481,7 +481,7 @@ FILE_VERSION_FILTER =
# The QUIET tag can be used to turn on/off the messages that are generated
# by doxygen. Possible values are YES and NO. If left blank NO is used.
QUIET = NO
QUIET = YES
# The WARNINGS tag can be used to turn on/off the warning messages that are
# generated by doxygen. Possible values are YES and NO. If left blank
@@ -534,7 +534,7 @@ WARN_LOGFILE =
# directories like "/usr/src/myproject". Separate the files or directories
# with spaces.
INPUT = src/
INPUT = @abs_top_srcdir@/src/
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is

@@ -69,6 +69,9 @@ mpd will be saved to this file when mpd is terminated by a TERM signal or by
the "kill" command. When mpd is restarted, it will read the state file and
restore the state of mpd (including the playlist).
.TP
.B restore_paused <yes or no>
Put MPD into pause mode instead of starting playback after startup.
.TP
.B user <username>
This specifies the user that MPD will run as, if set. MPD should
never run as root, and you may use this option to make MPD change its
@@ -80,6 +83,10 @@ This specifies which address mpd binds to and listens on. Multiple
bind_to_address parameters may be specified. The default is "any", which binds
to all available addresses.
You can set a port that is different from the global port setting,
e.g. "localhost:6602". IPv6 addresses must be enclosed in square
brackets if you want to configure a port, e.g. "[::1]:6602".
To bind to a Unix domain socket, specify an absolute path. For a
system-wide MPD, we suggest the path "\fB/var/run/mpd/socket\fP".
.TP
@@ -209,7 +216,7 @@ default is 5.
.TP
.B max_playlist_length <number>
This specifies the maximum number of songs that can be in the playlist. The
default is 4096.
default is 16384.
.TP
.B max_command_list_size <size in KiB>
This specifies the maximum size a command list can be. The default is 2048.
@@ -245,11 +252,12 @@ when saving playlists. The default is "no".
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
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.
track, name, genre, date, composer, performer, comment, disc,
musicbrainz_artistid, musicbrainz_albumid, musicbrainz_albumartistid,
musicbrainz_trackid. Multiple 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 and those starting with "musicbrainz".
.TP
.B auto_update <yes or no>
This specifies the wheter to support automatic update of music database when
@@ -259,6 +267,17 @@ of database.
.B auto_update_depth <N>
Limit the depth of the directories being watched, 0 means only watch
the music directory itself. There is no limit by default.
.TP
.B despotify_user <name>
This specifies the user to use when logging in to Spotify using the despotify plugins.
.TP
.B despotify_password <name>
This specifies the password to use when logging in to Spotify using the despotify plugins.
.TP
.B despotify_high_bitrate <yes or no>
This specifies if the requested bitrate for Spotify should be high or not. Higher sounds
better but requires more processing and higher bandwidth. Default is yes.
.TP
.SH REQUIRED AUDIO OUTPUT PARAMETERS
.TP
.B type <type>
@@ -464,8 +483,26 @@ connect to the icecast server. The default is 2 seconds.
.B description <description>
This specifies a description of the stream.
.TP
.B url <url>
This specifies a URL associated with the stream.
.TP
.B genre <genre>
This specifies the genre(s) of the stream.
.SH OPTIONAL TCP KEEPALIVE PARAMETERS
.TP
.B tcp_keep_alive <yes or no>
Enable tcp keepalive on new client connections. (default is "no")
.TP
.B tcp_keep_alive_idle <seconds>
Time in seconds since the last communication on the connection and before
the keepalive probing is started. (default is 7200 seconds)
.TP
.B tcp_keep_alive_interval <seconds>
Interval in seconds between keepalive probes, once a probe started. (default is 75 seconds)
.TP
.B tcp_keep_alive_count <number of times>
Number of failed probes before the connection is pronounced dead and
the connection is closed. (default is 9 times)
.SH FILES
.TP
.BI ~/.mpdconf

@@ -103,15 +103,19 @@
#
#gapless_mp3_playback "yes"
#
# Setting "restore_paused" to "yes" puts MPD into pause mode instead
# of starting playback after startup.
#
#restore_paused "no"
#
# This setting enables MPD to create playlists in a format usable by other
# music players.
#
#save_absolute_paths_in_playlists "no"
#
# This setting defines a list of tag types that will be extracted during the
# audio file discovery process. Optionally, 'comment' can be added to this
# list.
#
# This setting defines a list of tag types that will be extracted during the
# audio file discovery process. The complete list of possible values can be
# found in the mpd.conf man page.
#metadata_to_use "artist,album,title,track,name,genre,date,composer,performer,disc"
#
# This setting enables automatic update of MPD's database when files in
@@ -235,6 +239,7 @@ input {
## protocol "icecast2" # optional
## user "source" # optional
## description "My Stream Description" # optional
## url "http://example.com" # optional
## genre "jazz" # optional
## public "no" # optional
## timeout "2" # optional
@@ -366,6 +371,35 @@ input {
#
###############################################################################
# Client TCP keep alive #######################################################
#
# For clients connected by TCP on supported platforms.
# Allows detection of dangling connections due to clients disappearing from
# the network without closing their connections.
#
# This is not usually necessary but can be useful in cases such as wifi connectected
# clients that go in and out of network range or turn off wifi without closing their
# connections. Combined with low max_connections this can soon cause clients to not
# be able to connect.
#
#
# Enable tcp keepalive on new client connections (default is "no")
#
#tcp_keep_alive "no"
#
# Time in seconds since the last communication on the connection and before
# the keepalive probing is started. (default is 7200 seconds)
#tcp_keep_alive_idle "7200"
#
# Interval in seconds between keepalive probes, once a probe started.
# (default is 75 seconds)
#tcp_keep_alive_interval "75"
#
# Number of failed probes before the connection is pronounced dead and
# the connection is closed. (default is 9 times)
#tcp_keep_alive_count "9"
#
###############################################################################
# Character Encoding ##########################################################
#

@@ -8,22 +8,58 @@
<title>General protocol syntax</title>
<section>
<title>Requests</title>
<title>Protocol overview</title>
<para>
If arguments contain spaces, they should be surrounded by double quotation
marks.
The MPD command protocol exchanges line-based text records
between client and server over TCP. Once the client is
connected to the server, they conduct a conversation until the
client closes the connection. The conversation flow is always
initiated by the client.
</para>
<para>
The client transmits a command sequence, terminated by the
newline character <constant>\n</constant>. The server will
respond with one or more lines, the last of which will be a
completion code.
</para>
<para>
When the client connects to the server, the server will answer
with the following line:
<synopsis>OK MPD version</synopsis>
where <varname>version</varname> is a version identifier such as
0.12.2. This version identifier is the version of the protocol
spoken, not the real version of the daemon. (There is no way to
retrieve this real version identifier from the connection.)
</para>
</section>
<section>
<title>Requests</title>
<cmdsynopsis>
<command>COMMAND</command>
<arg rep="repeat"><replaceable>ARG</replaceable></arg>
</cmdsynopsis>
<para>
If arguments contain spaces, they should be surrounded by double
quotation marks.
</para>
<para>
Argument strings are separated from the command and any other
arguments by linear white-space (' ' or '\t').
</para>
<para>
All data between the client and the server is encoded in
UTF-8. (Note: In UTF-8 all standard ansi characters, 0-127 are
the same as a standard ansi encoding. Also, no ansi character
the same as in standard ansi encoding. Also, no ansi character
appears in any multi-byte characters. So, you can use
standard C functions like <function>strlen</function>, and
<function>strcpy</function> just fine with UTF-8 encoded
@@ -38,13 +74,97 @@
<title>Responses</title>
<para>
A command returns <returnvalue>OK</returnvalue> on completion
or <returnvalue>ACK some error</returnvalue> on failure.
These denote the end of command execution.
A command returns <returnvalue>OK</returnvalue> on completion or
<returnvalue>ACK some error</returnvalue> on failure. These
denote the end of command execution.
</para>
<section>
<title>Failure responses</title>
<para>
The nature of the error can be gleaned from the information
that follows the <returnvalue>ACK</returnvalue>.
<returnvalue>ACK</returnvalue> lines are of the form:
<synopsis>ACK [error@command_listNum] {current_command} message_text\n</synopsis>
These responses are generated by a call to
<function>commandError</function>. They contain four separate
terms. Let's look at each of them:
<itemizedlist>
<listitem>
<para>
<returnvalue>error</returnvalue>: numeric value of one
of the <constant>ACK_ERROR</constant> constants defined
in <filename>ack.h</filename>.
</para>
</listitem>
<listitem>
<para>
<returnvalue>command_listNum</returnvalue>:
offset of the command that caused the error in a <link
linkend="command_lists">Command List</link>.
An error will always cause a command list to terminate
at the command that causes the error.
</para>
</listitem>
<listitem>
<para>
<returnvalue>current_command</returnvalue>:
name of the command, in a <link
linkend="command_lists">Command List</link>,
that was executing when the error occurred.
</para>
</listitem>
<listitem>
<para>
<returnvalue>message_text</returnvalue>:
some (hopefully) informative text that describes the
nature of the error.
</para>
</listitem>
</itemizedlist>
</para>
<example>
<title>foo</title>
<para>
An example might help. Consider the following sequence
sent from the client to the server.
<synopsis>
command_list_begin
volume 86
play 10240
status
command_list_end
</synopsis>
</para>
<para>
The server responds with:
<returnvalue>
ACK [50@1] {play} song doesn't exist: "10240"
</returnvalue>
</para>
<para>
This tells us that the play command, which was the
second in the list (the first or only command is
numbered 0), failed with error 50. The number 50
translates to <constant>ACK_ERROR_NO_EXIST</constant>--the
song doesn't exist. This is reiterated by the message text
which also tells us which song doesn't exist.
</para>
</example>
</section>
</section>
<section>
<section id="command_lists">
<title>Command lists</title>
<para>
@@ -83,6 +203,47 @@
</section>
</chapter>
<chapter>
<title>Recipes</title>
<section>
<title>Queuing</title>
<para>
Often, users run MPD with "<link
linkend="command_random">random</link>" enabled, but want to
be able to insert songs "before" the rest of the playlist.
That is commonly called "queuing".
</para>
<para>
MPD implements this by allowing the client to specify a
"priority" for each song in the playlist (commands <link
linkend="command_prio"><command>prio</command></link> and
<link
linkend="command_prioid"><command>prioid</command></link>). A
higher priority means that the song is going to be played
before the other songs.
</para>
<para>
In "random" mode, MPD maintains an internal randomized
sequence of songs. In this sequence, songs with a higher
priority come first, and all songs with the same priority are
shuffled (by default, all songs are shuffled, because all have
the same priority "0"). When you increase the priority of a
song, it is moved to the front of the sequence according to
its new priority, but always after the current one. A song
that has been played already (it's "before" the current song
in that sequence) will only be scheduled for repeated playback
if its priority has become bigger than the priority of the
current song. Decreasing the priority of a song will moved it
farther to the end of the sequence. Changing the priority of
the current song has no effect on the sequence.
</para>
</section>
</chapter>
<chapter>
<title>Command reference</title>
@@ -198,6 +359,25 @@
<option>crossfade</option>, replay gain
</para>
</listitem>
<listitem>
<para>
<returnvalue>sticker</returnvalue>: the sticker database
has been modified.
</para>
</listitem>
<listitem>
<para>
<returnvalue>subscription</returnvalue>: a client
has subscribed or unsubscribed to a channel
</para>
</listitem>
<listitem>
<para>
<returnvalue>message</returnvalue>: a message was
received on a channel this client is subscribed to;
this event is only emitted when the queue is empty
</para>
</listitem>
</itemizedlist>
<para>
While a client is waiting for <command>idle</command>
@@ -364,7 +544,7 @@
</listitem>
<listitem>
<para>
<varname>updatings_db</varname>:
<varname>updating_db</varname>:
<returnvalue>job id</returnvalue>
</para>
</listitem>
@@ -557,7 +737,11 @@
Sets the replay gain mode. One of
<parameter>off</parameter>,
<parameter>track</parameter>,
<parameter>album</parameter>.
<parameter>album</parameter>,
<parameter>auto</parameter><footnote
id="replay_gain_auto_since_0_16">
<simpara>added in MPD 0.16</simpara>
</footnote>.
</para>
<para>
Changing the mode during playback may take several
@@ -694,6 +878,23 @@
</para>
</listitem>
</varlistentry>
<varlistentry id="command_seekcur">
<term>
<cmdsynopsis>
<command>seekcur</command>
<arg choice="req"><replaceable>TIME</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Seeks to the position <varname>TIME</varname> within the
current song. If prefixed by '+' or '-', then the time
is relative to the current playing position.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_stop">
<term>
<cmdsynopsis>
@@ -953,6 +1154,46 @@ OK
</para>
</listitem>
</varlistentry>
<varlistentry id="command_prio">
<term>
<cmdsynopsis>
<command>prio</command>
<arg choice="req"><replaceable>PRIORITY</replaceable></arg>
<arg choice="req" rep="repeat"><replaceable>START:END</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Set the priority of the specified songs. A higher
priority means that it will be played first when
"random" mode is enabled.
</para>
<para>
A priority is an integer between 0 and 255. The default
priority of new songs is 0.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_prioid">
<term>
<cmdsynopsis>
<command>prioid</command>
<arg choice="req"><replaceable>PRIORITY</replaceable></arg>
<arg choice="req" rep="repeat"><replaceable>ID</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Same as <link
linkend="command_prio"><command>prio</command></link>,
but address the songs with their id.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_shuffle">
<term>
<cmdsynopsis>
@@ -1071,12 +1312,14 @@ OK
<cmdsynopsis>
<command>load</command>
<arg choice="req"><replaceable>NAME</replaceable></arg>
<arg choice="opt"><replaceable>START:END</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Loads the playlist into the current queue. Playlist
plugins are supported.
plugins are supported. A range may be specified to load
only a part of the playlist.
</para>
</listitem>
</varlistentry>
@@ -1313,6 +1556,11 @@ OK
the list of stored playlists. This behavior is
deprecated; use "listplaylists" instead.
</para>
<para>
Clients that are connected via UNIX domain socket may
use this command to read the tags of an arbitrary local
file (URI beginning with "file:///").
</para>
</listitem>
</varlistentry>
<varlistentry id="command_search">
@@ -1333,6 +1581,51 @@ OK
</para>
</listitem>
</varlistentry>
<varlistentry id="command_searchadd">
<term>
<cmdsynopsis>
<command>searchadd</command>
<arg choice="req"><replaceable>TYPE</replaceable></arg>
<arg choice="req"><replaceable>WHAT</replaceable></arg>
<arg choice="opt"><replaceable>...</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Searches for any song that contains <varname>WHAT</varname>
in tag <varname>TYPE</varname> and adds them to current playlist.
</para>
<para>
Parameters have the same meaning as for <command>find</command>,
except that search is not case sensitive.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_searchaddpl">
<term>
<cmdsynopsis>
<command>searchaddpl</command>
<arg choice="req"><replaceable>NAME</replaceable></arg>
<arg choice="req"><replaceable>TYPE</replaceable></arg>
<arg choice="req"><replaceable>WHAT</replaceable></arg>
<arg choice="opt"><replaceable>...</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Searches for any song that contains <varname>WHAT</varname>
in tag <varname>TYPE</varname> and adds them to the playlist
named <varname>NAME</varname>.
</para>
<para>
If a playlist by that name doesn't exist it is created.
</para>
<para>
Parameters have the same meaning as for <command>find</command>,
except that search is not case sensitive.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_update">
<term>
<cmdsynopsis>
@@ -1561,6 +1854,7 @@ OK
<term>
<cmdsynopsis>
<command>disableoutput</command>
<arg choice="req"><replaceable>ID</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
@@ -1573,6 +1867,7 @@ OK
<term>
<cmdsynopsis>
<command>enableoutput</command>
<arg choice="req"><replaceable>ID</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
@@ -1600,6 +1895,47 @@ OK
<title>Reflection</title>
<variablelist>
<varlistentry id="command_config">
<term>
<cmdsynopsis>
<command>config</command>
</cmdsynopsis>
</term>
<listitem>
<para>
Dumps configuration values that may be interesting for
the client. This command is only permitted to "local"
clients (connected via UNIX domain socket).
</para>
<para>
The following response attributes are available:
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>
Name
</entry>
<entry>
Description
</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>music_directory</varname>
</entry>
<entry>
The absolute path of the music directory.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</listitem>
</varlistentry>
<varlistentry id="command_commands">
<term>
<cmdsynopsis>
@@ -1670,5 +2006,105 @@ suffix: mpc</programlisting>
</varlistentry>
</variablelist>
</section>
<section>
<title>Client to client</title>
<para>
Clients can communicate with each others over "channels". A
channel is created by a client subscribing to it. More than
one client can be subscribed to a channel at a time; all of
them will receive the messages which get sent to it.
</para>
<para>
Each time a client subscribes or unsubscribes, the global idle
event <varname>subscription</varname> is generated. In
conjunction with the <command>channels</command> command, this
may be used to auto-detect clients providing additional
services.
</para>
<para>
New messages are indicated by the <varname>message</varname>
idle event.
</para>
<variablelist>
<varlistentry id="command_subscribe">
<term>
<cmdsynopsis>
<command>subscribe</command>
<arg choice="req"><replaceable>NAME</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Subscribe to a channel. The channel is created if it
does not exist already. The name may consist of
alphanumeric ASCII characters plus underscore, dash, dot
and colon.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_unsubscribe">
<term>
<cmdsynopsis>
<command>unsubscribe</command>
<arg choice="req"><replaceable>NAME</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Unsubscribe from a channel.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_channels">
<term>
<cmdsynopsis>
<command>channels</command>
</cmdsynopsis>
</term>
<listitem>
<para>
Obtain a list of all channels. The response is a list
of "channel:" lines.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_readmessages">
<term>
<cmdsynopsis>
<command>readmessages</command>
</cmdsynopsis>
</term>
<listitem>
<para>
Reads messages for this client. The response is a list
of "channel:" and "message:" lines.
</para>
</listitem>
</varlistentry>
<varlistentry id="command_sendmessage">
<term>
<cmdsynopsis>
<command>sendmessage</command>
<arg choice="req"><replaceable>CHANNEL</replaceable></arg>
<arg choice="req"><replaceable>TEXT</replaceable></arg>
</cmdsynopsis>
</term>
<listitem>
<para>
Send a message to the specified channel.
</para>
</listitem>
</varlistentry>
</variablelist>
</section>
</chapter>
</book>

@@ -99,6 +99,47 @@ cd mpd-version</programlisting>
<programlisting>make install</programlisting>
</section>
<section>
<title><filename>systemd</filename> socket activation</title>
<para>
Using <filename>systemd</filename>, you can launch
<filename>mpd</filename> on demand when the first client
attempts to connect. Create two files in
<filename>/etc/systemd/system/</filename>; first
<filename>mpd.socket</filename>:
</para>
<programlisting>[Socket]
ListenStream=/run/mpd.socket
ListenStream=6600
[Install]
WantedBy=sockets.target</programlisting>
<para>
Now create <filename>mpd.service</filename>:
</para>
<programlisting>[Unit]
Description=Music Player Daemon
After=sound.target
[Service]
ExecStart=/usr/bin/mpd --stdout --no-daemon</programlisting>
<para>
Start the socket:
</para>
<programlisting>systemctl enable mpd.socket
systemctl start mpd.socket</programlisting>
<para>
In this configuration, <filename>mpd</filename> will ignore
the <varname>bind_to_address</varname> and
<varname>port</varname> settings.
</para>
</section>
</chapter>
<chapter>
@@ -235,6 +276,16 @@ cd mpd-version</programlisting>
</informaltable>
</section>
<section>
<title>Configuring encoder plugins</title>
<para>
Encoders are used by some of the output plugins (such as
<varname>shout</varname>). The encoder settings are included
in the <varname>audio_output</varname> section.
</para>
</section>
<section>
<title>Configuring audio outputs</title>
@@ -322,7 +373,8 @@ cd mpd-version</programlisting>
<varname>24_3</varname> (signed 24 bit integer
samples, no padding, 3 bytes per sample),
<varname>32</varname> (signed 32 bit integer
samples).
samples), <varname>f</varname> (32 bit floating
point, -1.0 to 1.0).
</para>
</entry>
</row>
@@ -346,7 +398,7 @@ cd mpd-version</programlisting>
If set to "yes", then MPD attempts to keep this audio
output always open. This may be useful for streaming
servers, when you don't want to disconnect all
listeners even when playback is accidently stopped.
listeners even when playback is accidentally stopped.
</entry>
</row>
<row>
@@ -446,7 +498,7 @@ cd mpd-version</programlisting>
</para>
<para>
To configure a filter, add a
To configure a playlist plugin, add a
<varname>playlist_plugin</varname> block to
<filename>mpd.conf</filename>:
</para>
@@ -621,11 +673,191 @@ cd mpd-version</programlisting>
Plays streams with the MMS protocol.
</para>
</section>
<section>
<title><varname>cdio_paranoia</varname></title>
<para>
Plays audio CDs. The URI has the form:
"<filename>cdda://[DEVICE][/TRACK]</filename>". The
simplest form <filename>cdda://</filename> plays the whole
disc in the default drive.
</para>
</section>
<section>
<title><varname>despotify</varname></title>
<para>
Plays <ulink url="http://www.spotify.com">Spotify</ulink> tracks using the despotify
library. The despotify plugin uses a <filename>spt://</filename> URI and a Spotify
URL. So for example, you can add a song with:
</para>
<para>
<filename>mpc add spt://spotify:track:5qENVY0YEdZ7fiuOax70x1</filename>
</para>
<para>
You need a Spotify premium account to use this plugin, and you need
to setup username and password in the configuration file. The
configuration settings are global since the despotify playlist plugin
use the same settings.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>despotify_user</varname>
</entry>
<entry>
Sets up the Spotify username (required)
</entry>
</row>
<row>
<entry>
<varname>despotify_password</varname>
</entry>
<entry>
Sets up the Spotify password (required)
</entry>
</row>
<row>
<entry>
<varname>despotify_high_bitrate</varname>
</entry>
<entry>
Set up if high bitrate should be used for Spotify tunes.
High bitrate sounds better but slow systems can have problems
with playback (default yes).
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>soup</varname></title>
<para>
Opens remote files or streams over HTTP.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>proxy</varname>
</entry>
<entry>
Sets the address of the HTTP proxy server.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
</section>
<section>
<title>Decoder plugins</title>
<section>
<title><varname>dsdiff</varname></title>
<para>
Decodes DFF files containing DSDIFF data (e.g. SACD rips).
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>lsbitfirst</varname>
<parameter>yes|no</parameter>
</entry>
<entry>
Decode the least significant bit first. Default is
"no".
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>dsf</varname></title>
<para>
Decodes DSF files containing DSDIFF data (e.g. SACD rips).
</para>
</section>
<section>
<title><varname>fluidsynth</varname></title>
<para>
MIDI decoder based on libfluidsynth.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>sample_rate</varname>
</entry>
<entry>
The sample rate that shall be synthesized by the
plugin. Defaults to 48000.
</entry>
</row>
<row>
<entry>
<varname>soundfont</varname>
</entry>
<entry>
The absolute path of the soundfont file. Defaults
to
<filename>/usr/share/sounds/sf2/FluidR3_GM.sf2</filename>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>mikmod</varname></title>
@@ -655,6 +887,209 @@ cd mpd-version</programlisting>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>wildmidi</varname></title>
<para>
MIDI decoder based on libwildmidi.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>config_file</varname>
</entry>
<entry>
The absolute path of the timidity config file. Defaults
to
<filename>/etc/timidity/timidity.cfg</filename>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
</section>
<section>
<title>Encoder plugins</title>
<section>
<title><varname>flac</varname></title>
<para>
Encodes into FLAC (lossless).
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>compression</varname>
</entry>
<entry>
Sets the <filename>libFLAC</filename> compression
level. The levels range from 0 (fastest, least
compression) to 8 (slowest, most compression).
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>lame</varname></title>
<para>
Encodes into MP3 using the LAME library.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>quality</varname>
</entry>
<entry>
Sets the quality for VBR. 0 is the highest quality,
9 is the lowest quality. Cannot be used with
<varname>bitrate</varname>.
</entry>
</row>
<row>
<entry>
<varname>bitrate</varname>
</entry>
<entry>
Sets the bit rate in kilobit per second. Cannot be
used with <varname>quality</varname>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>null</varname></title>
<para>
Does not encode anything, passes the input PCM data as-is.
</para>
</section>
<section>
<title><varname>twolame</varname></title>
<para>
Encodes into MP2 using the <filename>twolame</filename>
library.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>quality</varname>
</entry>
<entry>
Sets the quality for VBR. 0 is the highest quality,
9 is the lowest quality. Cannot be used with
<varname>bitrate</varname>.
</entry>
</row>
<row>
<entry>
<varname>bitrate</varname>
</entry>
<entry>
Sets the bit rate in kilobit per second. Cannot be
used with <varname>quality</varname>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>vorbis</varname></title>
<para>
Encodes into Ogg Vorbis.
</para>
<informaltable>
<tgroup cols="2">
<thead>
<row>
<entry>Setting</entry>
<entry>Description</entry>
</row>
</thead>
<tbody>
<row>
<entry>
<varname>quality</varname>
</entry>
<entry>
Sets the quality for VBR. -1 is the lowest quality,
10 is the highest quality. Cannot be used with
<varname>bitrate</varname>.
</entry>
</row>
<row>
<entry>
<varname>bitrate</varname>
</entry>
<entry>
Sets the bit rate in kilobit per second. Cannot be
used with <varname>quality</varname>.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
</section>
<section>
<title><varname>wave</varname></title>
<para>
Encodes into WAV (lossless).
</para>
</section>
</section>
<section>
@@ -764,6 +1199,23 @@ cd mpd-version</programlisting>
bit, floating point, ...).
</entry>
</row>
<row>
<entry>
<varname>dsd_usb</varname>
<parameter>yes|no</parameter>
</entry>
<entry>
If set to <parameter>yes</parameter>, then DSD over
USB according to the <ulink
url="http://www.sonore.us/DoP_openStandard_1v1.pdf">pro
posed standard by dCS and others</ulink> is enabled. This wraps
DSD samples in fake 24 bit PCM, and is understood by
some DSD capable products, but may be harmful to
other hardware. Therefore, the default is
<parameter>no</parameter> and you can enable the
option at your own risk.
</entry>
</row>
</tbody>
</tgroup>
</informaltable>
@@ -1364,6 +1816,15 @@ cd mpd-version</programlisting>
Sets a short description of the stream (optional).
</entry>
</row>
<row>
<entry>
<varname>url</varname>
<parameter>URL</parameter>
</entry>
<entry>
Sets a URL associated with the stream (optional).
</entry>
</row>
<row>
<entry>
<varname>public</varname>
@@ -1466,6 +1927,14 @@ cd mpd-version</programlisting>
</informaltable>
</section>
<section>
<title><varname>embcue</varname></title>
<para>
Reads CUE sheets from the "CUESHEET" tag of song files.
</para>
</section>
<section>
<title><varname>m3u</varname></title>
@@ -1498,6 +1967,27 @@ cd mpd-version</programlisting>
playlist files.
</para>
</section>
<section>
<title><varname>despotify</varname></title>
<para>
Adds <ulink url="http://www.spotify.com/">Spotify</ulink>
playlists. Spotify playlists use the <filename>spt://</filename> URI,
and a Spotify playlist URL. So for example, you can load a playlist
with
</para>
<para>
<filename>mpc load spt://spotify:user:simon.kagstrom:playlist:3SUwkOe5VbVHysZcidEZtH</filename>
</para>
<para>
See the despotify input plugin for configuration options (username
and password needs to be setup)
</para>
</section>
</section>
</chapter>
</book>

@@ -0,0 +1,63 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_compile_flags.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_COMPILE_FLAGS([FLAG1 FLAG2 ...], [FLAGS-VARIABLE], [EXTRA-FLAGS])
#
# DESCRIPTION
#
# For every FLAG1, FLAG2 it is checked whether the compiler works with the
# flag. If it does, the flag is added FLAGS-VARIABLE
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. During the check the flag is always added to the
# current language's flags.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# NOTE: This macro depends on the AX_APPEND_FLAG and
# AX_CHECK_COMPILE_FLAG. Please keep this macro in sync with
# AX_APPEND_LINK_FLAGS.
#
# LICENSE
#
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 2
AC_DEFUN([AX_APPEND_COMPILE_FLAGS],
[for flag in $1; do
AX_CHECK_COMPILE_FLAG([$flag], [AX_APPEND_FLAG([$flag], [$2])], [], [$3])
done
])dnl AX_APPEND_COMPILE_FLAGS

69
m4/ax_append_flag.m4 Normal file

@@ -0,0 +1,69 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_append_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_APPEND_FLAG(FLAG, [FLAGS-VARIABLE])
#
# DESCRIPTION
#
# FLAG is appended to the FLAGS-VARIABLE shell variable, with a space
# added in between.
#
# If FLAGS-VARIABLE is not specified, the current language's flags (e.g.
# CFLAGS) is used. FLAGS-VARIABLE is not changed if it already contains
# FLAG. If FLAGS-VARIABLE is unset in the shell, it is set to exactly
# FLAG.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 2
AC_DEFUN([AX_APPEND_FLAG],
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
AS_VAR_PUSHDEF([FLAGS], [m4_default($2,_AC_LANG_PREFIX[FLAGS])])dnl
AS_VAR_SET_IF(FLAGS,
[case " AS_VAR_GET(FLAGS) " in
*" $1 "*)
AC_RUN_LOG([: FLAGS already contains $1])
;;
*)
AC_RUN_LOG([: FLAGS="$FLAGS $1"])
AS_VAR_SET(FLAGS, ["AS_VAR_GET(FLAGS) $1"])
;;
esac],
[AS_VAR_SET(FLAGS,["$1"])])
AS_VAR_POPDEF([FLAGS])dnl
])dnl AX_APPEND_FLAG

@@ -0,0 +1,72 @@
# ===========================================================================
# http://www.gnu.org/software/autoconf-archive/ax_check_compile_flag.html
# ===========================================================================
#
# SYNOPSIS
#
# AX_CHECK_COMPILE_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS])
#
# DESCRIPTION
#
# Check whether the given FLAG works with the current language's compiler
# or gives an error. (Warnings, however, are ignored)
#
# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
# success/failure.
#
# If EXTRA-FLAGS is defined, it is added to the current language's default
# flags (e.g. CFLAGS) when the check is done. The check is thus made with
# the flags: "CFLAGS EXTRA-FLAGS FLAG". This can for example be used to
# force the compiler to issue an error when a bad flag is given.
#
# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
# macro in sync with AX_CHECK_{PREPROC,LINK}_FLAG.
#
# LICENSE
#
# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
#
# 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 3 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, see <http://www.gnu.org/licenses/>.
#
# As a special exception, the respective Autoconf Macro's copyright owner
# gives unlimited permission to copy, distribute and modify the configure
# scripts that are the output of Autoconf when processing the Macro. You
# need not follow the terms of the GNU General Public License when using
# or distributing such scripts, even though portions of the text of the
# Macro appear in them. The GNU General Public License (GPL) does govern
# all other use of the material that constitutes the Autoconf Macro.
#
# This special exception to the GPL applies to versions of the Autoconf
# Macro released by the Autoconf Archive. When you make and distribute a
# modified version of the Autoconf Macro, you may extend this special
# exception to the GPL to apply to your modified version as well.
#serial 2
AC_DEFUN([AX_CHECK_COMPILE_FLAG],
[AC_PREREQ(2.59)dnl for _AC_LANG_PREFIX
AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_[]_AC_LANG_ABBREV[]flags_$4_$1])dnl
AC_CACHE_CHECK([whether _AC_LANG compiler accepts $1], CACHEVAR, [
ax_check_save_flags=$[]_AC_LANG_PREFIX[]FLAGS
_AC_LANG_PREFIX[]FLAGS="$[]_AC_LANG_PREFIX[]FLAGS $4 $1"
AC_COMPILE_IFELSE([AC_LANG_PROGRAM()],
[AS_VAR_SET(CACHEVAR,[yes])],
[AS_VAR_SET(CACHEVAR,[no])])
_AC_LANG_PREFIX[]FLAGS=$ax_check_save_flags])
AS_IF([test x"AS_VAR_GET(CACHEVAR)" = xyes],
[m4_default([$2], :)],
[m4_default([$3], :)])
AS_VAR_POPDEF([CACHEVAR])dnl
])dnl AX_CHECK_COMPILE_FLAGS

@@ -39,8 +39,8 @@ if test x$enable_aac = xyes; then
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $MPD_CFLAGS $FAAD_CFLAGS -I."
LIBS="$LIBS $MPD_LIBS $FAAD_LIBS"
CFLAGS="$CFLAGS $FAAD_CFLAGS -I."
LIBS="$LIBS $FAAD_LIBS"
CPPFLAGS=$CFLAGS
AC_CHECK_HEADER(faad.h,,enable_aac=no)
if test x$enable_aac = xyes; then
@@ -50,10 +50,10 @@ if test x$enable_aac = xyes; then
AC_CHECK_DECL(faacDecInit2,,enable_aac=no,[#include <faad.h>])
fi
if test x$enable_aac = xyes; then
AC_CHECK_LIB(faad,faacDecInit2,[MPD_LIBS="$MPD_LIBS $FAAD_LIBS";MPD_CFLAGS="$MPD_CFLAGS $FAAD_CFLAGS"],enable_aac=no)
AC_CHECK_LIB(faad,faacDecInit2,,enable_aac=no)
if test x$enable_aac = xno; then
enable_aac=yes
AC_CHECK_LIB(faad,NeAACDecInit2,[MPD_LIBS="$MPD_LIBS $FAAD_LIBS";MPD_CFLAGS="$MPD_CFLAGS $FAAD_CFLAGS"],enable_aac=no)
AC_CHECK_LIB(faad,NeAACDecInit2,,enable_aac=no)
fi
fi
if test x$enable_aac = xyes; then
@@ -131,8 +131,8 @@ if test x$enable_aac = xyes; then
oldcflags=$CFLAGS
oldlibs=$LIBS
oldcppflags=$CPPFLAGS
CFLAGS="$CFLAGS $MPD_CFLAGS $FAAD_CFLAGS -Werror"
LIBS="$LIBS $MPD_LIBS $FAAD_LIBS"
CFLAGS="$CFLAGS $FAAD_CFLAGS -Werror"
LIBS="$LIBS $FAAD_LIBS"
CPPFLAGS=$CFLAGS
AC_MSG_CHECKING(for broken libfaad headers)
@@ -188,5 +188,11 @@ if test x$enable_aac = xyes; then
CPPFLAGS=$oldcppflags
else
enable_mp4=no
FAAD_CFLAGS=""
FAAD_LIBS=""
fi
AC_SUBST(FAAD_CFLAGS)
AC_SUBST(FAAD_LIBS)
])

@@ -63,3 +63,18 @@ AC_DEFUN([MPD_AUTO_PKG], [
MPD_AUTO_RESULT([$1], [$4], [$5])
])
dnl Check with pkg-config first, fall back to AC_CHECK_LIB.
dnl
dnl Parameters: varname1, varname2, pkgname, libname, symname, libs, cflags, description, errmsg
AC_DEFUN([MPD_AUTO_PKG_LIB], [
if eval "test x`echo '$'enable_$1` != xno"; then
PKG_CHECK_MODULES([$2], [$3],
[eval "found_$1=yes"],
AC_CHECK_LIB($4, $5,
[eval "found_$1=yes $2_LIBS='$6' $2_CFLAGS='$7'"],
[eval "found_$1=no"]))
fi
MPD_AUTO_RESULT([$1], [$8], [$9])
])

@@ -1,18 +0,0 @@
AC_DEFUN([MPD_CHECK_FLAG],[
var=`echo "$1" | tr "=-" "__"`
AC_CACHE_CHECK([whether the C compiler accepts $1],
[mpd_check_cflag_$var],[
save_CFLAGS="$CFLAGS"
CFLAGS="$CFLAGS $1"
AC_COMPILE_IFELSE([AC_LANG_SOURCE([
int main(void) { return 0; }
])], [ eval "mpd_check_cflag_$var=yes"
], [ eval "mpd_check_cflag_$var=no" ])
CFLAGS="$save_CFLAGS"
])
if eval "test x`echo '$mpd_check_cflag_'$var` = xyes"
then
AM_CFLAGS="$AM_CFLAGS $1"
fi
])
])

@@ -20,7 +20,7 @@ AC_DEFUN([STRUCT_UCRED],[
mpd_cv_have_struct_ucred=no)
if test x$mpd_cv_have_struct_ucred = xyes; then
# :(
MPD_CFLAGS="$MPD_CFLAGS -D_GNU_SOURCE"
CFLAGS="$CFLAGS -D_GNU_SOURCE"
fi
fi
])

9
mpd.service.in Normal file

@@ -0,0 +1,9 @@
[Unit]
Description=Music Player Daemon
After=sound.target
[Service]
ExecStart=@prefix@/bin/mpd --no-daemon
[Install]
WantedBy=multi-user.target

@@ -3,7 +3,7 @@ PWD=`pwd`
## If we're not in the scripts directory
## assume the base directory.
if test "`basename $PWD`" == "scripts"; then
if test "`basename $PWD`" = "scripts"; then
cd ../
else
MYOLDPWD=`pwd`
@@ -18,7 +18,7 @@ fi
make
make dist
if test "`basename $PWD`" == "scripts"; then
if test "`basename $PWD`" = "scripts"; then
cd contrib/
else
cd $MYOLDPWD

@@ -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;
};
@@ -33,6 +33,9 @@ struct Compressor {
struct Compressor *Compressor_new(unsigned int history)
{
struct Compressor *obj = malloc(sizeof(struct Compressor));
if (obj == NULL)
/* out of memory, not much we can do */
abort();
obj->prefs.target = TARGET;
obj->prefs.maxgain = GAINMAX;
@@ -41,9 +44,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;
}
@@ -61,6 +64,10 @@ void Compressor_delete(struct Compressor *obj)
static int *resizeArray(int *data, int newsz, int oldsz)
{
data = realloc(data, newsz*sizeof(int));
if (data == NULL)
/* out of memory, not much we can do */
abort();
if (newsz > oldsz)
memset(data + oldsz, 0, sizeof(int)*(newsz - oldsz));
return data;
@@ -70,7 +77,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 +89,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 +104,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 +131,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 +151,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;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,6 +20,8 @@
#ifndef MPD_ACK_H
#define MPD_ACK_H
#include <glib.h>
enum ack {
ACK_ERROR_NOT_LIST = 1,
ACK_ERROR_ARG = 2,
@@ -36,4 +38,14 @@ enum ack {
ACK_ERROR_EXIST = 56,
};
/**
* Quark for GError.domain; the code is an enum #ack.
*/
G_GNUC_CONST
static inline GQuark
ack_quark(void)
{
return g_quark_from_static_string("ack");
}
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -57,7 +57,7 @@ aiff_seek_id3(FILE *file)
ret = fstat(fileno(file), &st);
if (ret < 0) {
g_warning("Failed to stat file descriptor: %s",
strerror(errno));
g_strerror(errno));
return 0;
}
@@ -73,7 +73,8 @@ aiff_seek_id3(FILE *file)
if (size != 1 ||
memcmp(header.id, "FORM", 4) != 0 ||
GUINT32_FROM_BE(header.size) > (uint32_t)st.st_size ||
memcmp(header.format, "AIFF", 4) != 0)
(memcmp(header.format, "AIFF", 4) != 0 &&
memcmp(header.format, "AIFC", 4) != 0))
/* not a AIFF file */
return 0;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -60,8 +60,10 @@ ape_scan_internal(FILE *fp, tag_ape_callback_t callback, void *ctx)
assert(remaining > 10);
char *buffer = g_malloc(remaining);
if (fread(buffer, 1, remaining, fp) != remaining)
if (fread(buffer, 1, remaining, fp) != remaining) {
g_free(buffer);
return false;
}
/* read tags */
unsigned n = GUINT32_FROM_LE(footer.count);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "config.h"
#include "archive/bz2_archive_plugin.h"
#include "archive_api.h"
#include "input_internal.h"
#include "input_plugin.h"
#include "refcount.h"
@@ -102,6 +103,11 @@ bz2_destroy(struct bz2_input_stream *data)
/* archive open && listing routine */
#if GCC_CHECK_VERSION(4, 2)
/* workaround for a warning caused by G_STATIC_MUTEX_INIT */
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
static struct archive_file *
bz2_open(const char *pathname, GError **error_r)
{
@@ -113,7 +119,11 @@ bz2_open(const char *pathname, GError **error_r)
refcount_init(&context->ref);
//open archive
context->istream = input_stream_open(pathname, error_r);
static GStaticMutex mutex = G_STATIC_MUTEX_INIT;
context->istream = input_stream_open(pathname,
g_static_mutex_get_mutex(&mutex),
NULL,
error_r);
if (context->istream == NULL) {
g_free(context);
return NULL;
@@ -168,12 +178,15 @@ bz2_close(struct archive_file *file)
/* single archive handling */
static struct input_stream *
bz2_open_stream(struct archive_file *file, const char *path, GError **error_r)
bz2_open_stream(struct archive_file *file, const char *path,
GMutex *mutex, GCond *cond,
GError **error_r)
{
struct bz2_archive_file *context = (struct bz2_archive_file *) file;
struct bz2_input_stream *bis = g_new(struct bz2_input_stream, 1);
input_stream_init(&bis->base, &bz2_inputplugin, path);
input_stream_init(&bis->base, &bz2_inputplugin, path,
mutex, cond);
bis->archive = context;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -24,6 +24,7 @@
#include "config.h"
#include "archive/iso9660_archive_plugin.h"
#include "archive_api.h"
#include "input_internal.h"
#include "input_plugin.h"
#include "refcount.h"
@@ -172,15 +173,17 @@ struct iso9660_input_stream {
};
static struct input_stream *
iso9660_archive_open_stream(struct archive_file *file,
const char *pathname, GError **error_r)
iso9660_archive_open_stream(struct archive_file *file, const char *pathname,
GMutex *mutex, GCond *cond,
GError **error_r)
{
struct iso9660_archive_file *context =
(struct iso9660_archive_file *)file;
struct iso9660_input_stream *iis;
iis = g_new(struct iso9660_input_stream, 1);
input_stream_init(&iis->base, &iso9660_input_plugin, pathname);
input_stream_init(&iis->base, &iso9660_input_plugin, pathname,
mutex, cond);
iis->archive = context;
iis->statbuf = iso9660_ifs_stat_translate(context->iso, pathname);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,7 @@
#include "archive/zzip_archive_plugin.h"
#include "archive_api.h"
#include "archive_api.h"
#include "input_internal.h"
#include "input_plugin.h"
#include "refcount.h"
@@ -134,14 +135,17 @@ struct zzip_input_stream {
static struct input_stream *
zzip_archive_open_stream(struct archive_file *file,
const char *pathname, GError **error_r)
const char *pathname,
GMutex *mutex, GCond *cond,
GError **error_r)
{
struct zzip_archive *context = (struct zzip_archive *) file;
struct zzip_input_stream *zis;
ZZIP_STAT z_stat;
zis = g_new(struct zzip_input_stream, 1);
input_stream_init(&zis->base, &zzip_input_plugin, pathname);
input_stream_init(&zis->base, &zzip_input_plugin, pathname,
mutex, cond);
zis->archive = context;
zis->file = zzip_file_open(context->dir, pathname, 0);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,7 +20,7 @@
#include "config.h"
#include "archive_list.h"
#include "archive_plugin.h"
#include "utils.h"
#include "string_util.h"
#include "archive/bz2_archive_plugin.h"
#include "archive/iso9660_archive_plugin.h"
#include "archive/zzip_archive_plugin.h"
@@ -28,7 +28,7 @@
#include <string.h>
#include <glib.h>
static const struct archive_plugin *const archive_plugins[] = {
const struct archive_plugin *const archive_plugins[] = {
#ifdef HAVE_BZ2
&bz2_archive_plugin,
#endif
@@ -44,55 +44,34 @@ static const struct archive_plugin *const archive_plugins[] = {
/** which plugins have been initialized successfully? */
static bool archive_plugins_enabled[G_N_ELEMENTS(archive_plugins) - 1];
#define archive_plugins_for_each_enabled(plugin) \
archive_plugins_for_each(plugin) \
if (archive_plugins_enabled[archive_plugin_iterator - archive_plugins])
const struct archive_plugin *
archive_plugin_from_suffix(const char *suffix)
{
if (suffix == NULL)
return NULL;
for (unsigned i = 0; archive_plugins[i] != NULL; ++i) {
const struct archive_plugin *plugin = archive_plugins[i];
if (archive_plugins_enabled[i] &&
plugin->suffixes != NULL &&
string_array_contains(plugin->suffixes, suffix)) {
++i;
archive_plugins_for_each_enabled(plugin)
if (plugin->suffixes != NULL &&
string_array_contains(plugin->suffixes, suffix))
return plugin;
}
}
return NULL;
}
const struct archive_plugin *
archive_plugin_from_name(const char *name)
{
for (unsigned i = 0; archive_plugins[i] != NULL; ++i) {
const struct archive_plugin *plugin = archive_plugins[i];
if (archive_plugins_enabled[i] &&
strcmp(plugin->name, name) == 0)
archive_plugins_for_each_enabled(plugin)
if (strcmp(plugin->name, name) == 0)
return plugin;
}
return NULL;
}
void archive_plugin_print_all_suffixes(FILE * fp)
{
const char *const*suffixes;
for (unsigned i = 0; archive_plugins[i] != NULL; ++i) {
const struct archive_plugin *plugin = archive_plugins[i];
if (!archive_plugins_enabled[i])
continue;
suffixes = plugin->suffixes;
while (suffixes && *suffixes) {
fprintf(fp, "%s ", *suffixes);
suffixes++;
}
}
fprintf(fp, "\n");
fflush(fp);
}
void archive_plugin_init_all(void)
{
for (unsigned i = 0; archive_plugins[i] != NULL; ++i) {
@@ -104,10 +83,8 @@ void archive_plugin_init_all(void)
void archive_plugin_deinit_all(void)
{
for (unsigned i = 0; archive_plugins[i] != NULL; ++i) {
const struct archive_plugin *plugin = archive_plugins[i];
if (archive_plugins_enabled[i] && plugin->finish != NULL)
archive_plugins[i]->finish();
}
archive_plugins_for_each_enabled(plugin)
if (plugin->finish != NULL)
plugin->finish();
}

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,10 +20,16 @@
#ifndef MPD_ARCHIVE_LIST_H
#define MPD_ARCHIVE_LIST_H
#include <stdio.h>
struct archive_plugin;
extern const struct archive_plugin *const archive_plugins[];
#define archive_plugins_for_each(plugin) \
for (const struct archive_plugin *plugin, \
*const*archive_plugin_iterator = &archive_plugins[0]; \
(plugin = *archive_plugin_iterator) != NULL; \
++archive_plugin_iterator)
/* interface for using plugins */
const struct archive_plugin *
@@ -32,8 +38,6 @@ archive_plugin_from_suffix(const char *suffix);
const struct archive_plugin *
archive_plugin_from_name(const char *name);
void archive_plugin_print_all_suffixes(FILE * fp);
/* this is where we "load" all the "plugins" ;-) */
void archive_plugin_init_all(void);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -81,12 +81,14 @@ archive_file_scan_next(struct archive_file *file)
}
struct input_stream *
archive_file_open_stream(struct archive_file *file,
const char *path, GError **error_r)
archive_file_open_stream(struct archive_file *file, const char *path,
GMutex *mutex, GCond *cond,
GError **error_r)
{
assert(file != NULL);
assert(file->plugin != NULL);
assert(file->plugin->open_stream != NULL);
return file->plugin->open_stream(file, path, error_r);
return file->plugin->open_stream(file, path, mutex, cond,
error_r);
}

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -68,11 +68,12 @@ struct archive_plugin {
* Opens an input_stream of a file within the archive.
*
* @param path the path within the archive
* @param error_r location to store the error occuring, or
* @param error_r location to store the error occurring, or
* NULL to ignore errors
*/
struct input_stream *(*open_stream)(struct archive_file *af,
const char *path,
GMutex *mutex, GCond *cond,
GError **error_r);
/**
@@ -101,7 +102,8 @@ char *
archive_file_scan_next(struct archive_file *file);
struct input_stream *
archive_file_open_stream(struct archive_file *file,
const char *path, GError **error_r);
archive_file_open_stream(struct archive_file *file, const char *path,
GMutex *mutex, GCond *cond,
GError **error_r);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -28,6 +28,7 @@
/**
* The GLib quark used for errors reported by this library.
*/
G_GNUC_CONST
static inline GQuark
audio_format_quark(void)
{

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,7 +18,7 @@
*/
#include "config.h"
#include "audio.h"
#include "audio_config.h"
#include "audio_format.h"
#include "audio_parser.h"
#include "output_internal.h"

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -17,8 +17,8 @@
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef MPD_AUDIO_H
#define MPD_AUDIO_H
#ifndef MPD_AUDIO_CONFIG_H
#define MPD_AUDIO_CONFIG_H
#include <stdbool.h>

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -22,11 +22,24 @@
#include <assert.h>
#include <stdio.h>
#if G_BYTE_ORDER == G_BIG_ENDIAN
#define REVERSE_ENDIAN_SUFFIX "_le"
#else
#define REVERSE_ENDIAN_SUFFIX "_be"
#endif
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;
if (mask->format != SAMPLE_FORMAT_UNDEFINED)
af->format = mask->format;
if (mask->channels != 0)
af->channels = mask->channels;
assert(audio_format_valid(af));
}
const char *
sample_format_to_string(enum sample_format format)
@@ -41,14 +54,17 @@ sample_format_to_string(enum sample_format format)
case SAMPLE_FORMAT_S16:
return "16";
case SAMPLE_FORMAT_S24:
return "24_3";
case SAMPLE_FORMAT_S24_P32:
return "24";
case SAMPLE_FORMAT_S32:
return "32";
case SAMPLE_FORMAT_FLOAT:
return "f";
case SAMPLE_FORMAT_DSD:
return "dsd";
}
/* unreachable */
@@ -63,9 +79,8 @@ audio_format_to_string(const struct audio_format *af,
assert(af != NULL);
assert(s != NULL);
snprintf(s->buffer, sizeof(s->buffer), "%u:%s%s:%u",
snprintf(s->buffer, sizeof(s->buffer), "%u:%s:%u",
af->sample_rate, sample_format_to_string(af->format),
af->reverse_endian ? REVERSE_ENDIAN_SUFFIX : "",
af->channels);
return s->buffer;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,8 +20,10 @@
#ifndef MPD_AUDIO_FORMAT_H
#define MPD_AUDIO_FORMAT_H
#include <glib.h>
#include <stdint.h>
#include <stdbool.h>
#include <assert.h>
enum sample_format {
SAMPLE_FORMAT_UNDEFINED = 0,
@@ -29,11 +31,6 @@ enum sample_format {
SAMPLE_FORMAT_S8,
SAMPLE_FORMAT_S16,
/**
* Signed 24 bit integer samples, without padding.
*/
SAMPLE_FORMAT_S24,
/**
* Signed 24 bit integer samples, packed in 32 bit integers
* (the most significant byte is filled with the sign bit).
@@ -41,8 +38,22 @@ enum sample_format {
SAMPLE_FORMAT_S24_P32,
SAMPLE_FORMAT_S32,
/**
* 32 bit floating point samples in the host's format. The
* range is -1.0f to +1.0f.
*/
SAMPLE_FORMAT_FLOAT,
/**
* Direct Stream Digital. 1-bit samples; each frame has one
* byte (8 samples) per channel.
*/
SAMPLE_FORMAT_DSD,
};
static const unsigned MAX_CHANNELS = 8;
/**
* This structure describes the format of a raw PCM stream.
*/
@@ -65,13 +76,6 @@ struct audio_format {
* fully supported currently.
*/
uint8_t channels;
/**
* If zero, then samples are stored in host byte order. If
* nonzero, then samples are stored in the reverse host byte
* order.
*/
uint8_t reverse_endian;
};
/**
@@ -90,7 +94,6 @@ static inline void audio_format_clear(struct audio_format *af)
af->sample_rate = 0;
af->format = SAMPLE_FORMAT_UNDEFINED;
af->channels = 0;
af->reverse_endian = 0;
}
/**
@@ -104,7 +107,6 @@ static inline void audio_format_init(struct audio_format *af,
af->sample_rate = sample_rate;
af->format = (uint8_t)format;
af->channels = channels;
af->reverse_endian = 0;
}
/**
@@ -161,9 +163,10 @@ audio_valid_sample_format(enum sample_format format)
switch (format) {
case SAMPLE_FORMAT_S8:
case SAMPLE_FORMAT_S16:
case SAMPLE_FORMAT_S24:
case SAMPLE_FORMAT_S24_P32:
case SAMPLE_FORMAT_S32:
case SAMPLE_FORMAT_FLOAT:
case SAMPLE_FORMAT_DSD:
return true;
case SAMPLE_FORMAT_UNDEFINED:
@@ -179,13 +182,14 @@ audio_valid_sample_format(enum sample_format format)
static inline bool
audio_valid_channel_count(unsigned channels)
{
return channels >= 1 && channels <= 8;
return channels >= 1 && channels <= MAX_CHANNELS;
}
/**
* Returns false if the format is not valid for playback with MPD.
* This function performs some basic validity checks.
*/
G_GNUC_PURE
static inline bool audio_format_valid(const struct audio_format *af)
{
return audio_valid_sample_rate(af->sample_rate) &&
@@ -197,6 +201,7 @@ static inline bool audio_format_valid(const struct audio_format *af)
* Returns false if the format mask is not valid for playback with
* MPD. This function performs some basic validity checks.
*/
G_GNUC_PURE
static inline bool audio_format_mask_valid(const struct audio_format *af)
{
return (af->sample_rate == 0 ||
@@ -211,53 +216,54 @@ static inline bool audio_format_equals(const struct audio_format *a,
{
return a->sample_rate == b->sample_rate &&
a->format == b->format &&
a->channels == b->channels &&
a->reverse_endian == b->reverse_endian;
a->channels == b->channels;
}
static inline void
void
audio_format_mask_apply(struct audio_format *af,
const struct audio_format *mask)
const struct audio_format *mask);
G_GNUC_CONST
static inline unsigned
sample_format_size(enum sample_format format)
{
if (mask->sample_rate != 0)
af->sample_rate = mask->sample_rate;
if (mask->format != SAMPLE_FORMAT_UNDEFINED)
af->format = mask->format;
if (mask->channels != 0)
af->channels = mask->channels;
}
/**
* Returns the size of each (mono) sample in bytes.
*/
static inline unsigned audio_format_sample_size(const struct audio_format *af)
{
switch (af->format) {
switch (format) {
case SAMPLE_FORMAT_S8:
return 1;
case SAMPLE_FORMAT_S16:
return 2;
case SAMPLE_FORMAT_S24:
return 3;
case SAMPLE_FORMAT_S24_P32:
case SAMPLE_FORMAT_S32:
case SAMPLE_FORMAT_FLOAT:
return 4;
case SAMPLE_FORMAT_DSD:
/* each frame has 8 samples per channel */
return 1;
case SAMPLE_FORMAT_UNDEFINED:
break;
return 0;
}
assert(false);
return 0;
}
/**
* Returns the size of each (mono) sample in bytes.
*/
G_GNUC_PURE
static inline unsigned audio_format_sample_size(const struct audio_format *af)
{
return sample_format_size((enum sample_format)af->format);
}
/**
* Returns the size of each full frame in bytes.
*/
G_GNUC_PURE
static inline unsigned
audio_format_frame_size(const struct audio_format *af)
{
@@ -268,6 +274,7 @@ audio_format_frame_size(const struct audio_format *af)
* Returns the floating point factor which converts a time span to a
* storage size in bytes.
*/
G_GNUC_PURE
static inline double audio_format_time_to_size(const struct audio_format *af)
{
return af->sample_rate * audio_format_frame_size(af);
@@ -280,6 +287,7 @@ static inline double audio_format_time_to_size(const struct audio_format *af)
* @param format a #sample_format enum value
* @return the string
*/
G_GNUC_PURE G_GNUC_MALLOC
const char *
sample_format_to_string(enum sample_format format);
@@ -291,6 +299,7 @@ sample_format_to_string(enum sample_format format);
* @param s a buffer to print into
* @return the string, or NULL if the #audio_format object is invalid
*/
G_GNUC_PURE G_GNUC_MALLOC
const char *
audio_format_to_string(const struct audio_format *af,
struct audio_format_string *s);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -26,6 +26,7 @@
#include "audio_parser.h"
#include "audio_format.h"
#include "audio_check.h"
#include "gcc.h"
#include <assert.h>
#include <string.h>
@@ -81,6 +82,18 @@ parse_sample_format(const char *src, bool mask,
return true;
}
if (*src == 'f') {
*sample_format_r = SAMPLE_FORMAT_FLOAT;
*endptr_r = src + 1;
return true;
}
if (memcmp(src, "dsd", 3) == 0) {
*sample_format_r = SAMPLE_FORMAT_DSD;
*endptr_r = src + 3;
return true;
}
value = strtoul(src, &endptr, 10);
if (endptr == src) {
g_set_error(error_r, audio_parser_quark(), 0,
@@ -98,11 +111,11 @@ parse_sample_format(const char *src, bool mask,
break;
case 24:
if (memcmp(endptr, "_3", 2) == 0) {
sample_format = SAMPLE_FORMAT_S24;
if (memcmp(endptr, "_3", 2) == 0)
/* for backwards compatibility */
endptr += 2;
} else
sample_format = SAMPLE_FORMAT_S24_P32;
sample_format = SAMPLE_FORMAT_S24_P32;
break;
case 32:
@@ -160,6 +173,11 @@ audio_format_parse(struct audio_format *dest, const char *src,
/* parse sample rate */
#if GCC_CHECK_VERSION(4,7)
/* workaround -Wmaybe-uninitialized false positive */
rate = 0;
#endif
if (!parse_sample_rate(src, mask, &rate, &src, error_r))
return false;
@@ -171,6 +189,11 @@ audio_format_parse(struct audio_format *dest, const char *src,
/* parse sample format */
#if GCC_CHECK_VERSION(4,7)
/* workaround -Wmaybe-uninitialized false positive */
sample_format = SAMPLE_FORMAT_UNDEFINED;
#endif
if (!parse_sample_format(src, mask, &sample_format, &src, error_r))
return false;
@@ -192,6 +215,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;
}

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -38,7 +38,7 @@ struct audio_format;
* @param dest the destination #audio_format struct
* @param src the input string
* @param mask if true, then "*" is allowed for any number of items
* @param error_r location to store the error occuring, or NULL to
* @param error_r location to store the error occurring, or NULL to
* ignore errors
* @return true on success
*/

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -27,20 +27,36 @@
struct client;
struct sockaddr;
struct player_control;
void client_manager_init(void);
void client_manager_deinit(void);
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid);
void client_new(struct player_control *player_control,
int fd, const struct sockaddr *sa, size_t sa_length, int uid);
G_GNUC_PURE
bool client_is_expired(const struct client *client);
/**
* returns the uid of the client process, or a negative value if the
* uid is unknown
*/
G_GNUC_PURE
int client_get_uid(const struct client *client);
/**
* Is this client running on the same machine, connected with a local
* (UNIX domain) socket?
*/
G_GNUC_PURE
static inline bool
client_is_local(const struct client *client)
{
return client_get_uid(client) > 0;
}
G_GNUC_PURE
unsigned client_get_permission(const struct client *client);
void client_set_permission(struct client *client, unsigned permission);
@@ -60,17 +76,4 @@ void client_vprintf(struct client *client, const char *fmt, va_list args);
*/
G_GNUC_PRINTF(2, 3) void client_printf(struct client *client, const char *fmt, ...);
/**
* Adds the specified idle flags to all clients and immediately sends
* notifications to all waiting clients.
*/
void client_manager_idle_add(unsigned flags);
/**
* Checks whether the client has pending idle flags. If yes, they are
* sent immediately and "true" is returned". If no, it puts the
* client into waiting mode and returns false.
*/
bool client_idle_wait(struct client *client, unsigned flags);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

70
src/client_file.c Normal file

@@ -0,0 +1,70 @@
/*
* Copyright (C) 2003-2012 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 "client_file.h"
#include "client.h"
#include "ack.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <errno.h>
#include <unistd.h>
bool
client_allow_file(const struct client *client, const char *path_fs,
GError **error_r)
{
#ifdef WIN32
(void)client;
(void)path_fs;
g_set_error(error_r, ack_quark(), ACK_ERROR_PERMISSION,
"Access denied");
return false;
#else
const int uid = client_get_uid(client);
if (uid >= 0 && (uid_t)uid == geteuid())
/* always allow access if user runs his own MPD
instance */
return true;
if (uid <= 0) {
/* unauthenticated client */
g_set_error(error_r, ack_quark(), ACK_ERROR_PERMISSION,
"Access denied");
return false;
}
struct stat st;
if (stat(path_fs, &st) < 0) {
g_set_error(error_r, g_file_error_quark(), errno,
"%s", g_strerror(errno));
return false;
}
if (st.st_uid != (uid_t)uid && (st.st_mode & 0444) != 0444) {
/* client is not owner */
g_set_error(error_r, ack_quark(), ACK_ERROR_PERMISSION,
"Access denied");
return false;
}
return true;
#endif
}

42
src/client_file.h Normal file

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2003-2012 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_CLIENT_FILE_H
#define MPD_CLIENT_FILE_H
#include <glib.h>
#include <stdbool.h>
struct client;
/**
* Is this client allowed to use the specified local file?
*
* Note that this function is vulnerable to timing/symlink attacks.
* We cannot fix this as long as there are plugins that open a file by
* its name, and not by file descriptor / callbacks.
*
* @param path_fs the absolute path name in filesystem encoding
* @return true if access is allowed
*/
bool
client_allow_file(const struct client *client, const char *path_fs,
GError **error_r);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -18,6 +18,7 @@
*/
#include "config.h"
#include "client_idle.h"
#include "client_internal.h"
#include "idle.h"
@@ -50,12 +51,9 @@ client_idle_notify(struct client *client)
g_timer_start(client->last_activity);
}
static void
client_idle_callback(gpointer data, gpointer user_data)
void
client_idle_add(struct client *client, unsigned flags)
{
struct client *client = data;
unsigned flags = GPOINTER_TO_UINT(user_data);
if (client_is_expired(client))
return;
@@ -67,6 +65,15 @@ client_idle_callback(gpointer data, gpointer user_data)
}
}
static void
client_idle_callback(gpointer data, gpointer user_data)
{
struct client *client = data;
unsigned flags = GPOINTER_TO_UINT(user_data);
client_idle_add(client, flags);
}
void client_manager_idle_add(unsigned flags)
{
assert(flags != 0);

45
src/client_idle.h Normal file

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2003-2011 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_CLIENT_IDLE_H
#define MPD_CLIENT_IDLE_H
#include <stdbool.h>
struct client;
void
client_idle_add(struct client *client, unsigned flags);
/**
* Adds the specified idle flags to all clients and immediately sends
* notifications to all waiting clients.
*/
void
client_manager_idle_add(unsigned flags);
/**
* Checks whether the client has pending idle flags. If yes, they are
* sent immediately and "true" is returned". If no, it puts the
* client into waiting mode and returns false.
*/
bool
client_idle_wait(struct client *client, unsigned flags);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -21,17 +21,25 @@
#define MPD_CLIENT_INTERNAL_H
#include "client.h"
#include "client_message.h"
#include "command.h"
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "client"
enum {
CLIENT_MAX_SUBSCRIPTIONS = 16,
CLIENT_MAX_MESSAGES = 64,
};
struct deferred_buffer {
size_t size;
char data[sizeof(long)];
};
struct client {
struct player_control *player_control;
GIOChannel *channel;
guint source_id;
@@ -67,6 +75,28 @@ struct client {
/** idle flags that the client wants to receive */
unsigned idle_subscriptions;
/**
* A list of channel names this client is subscribed to.
*/
GSList *subscriptions;
/**
* The number of subscriptions in #subscriptions. Used to
* limit the number of subscriptions.
*/
unsigned num_subscriptions;
/**
* A list of messages this client has received in reverse
* order (latest first).
*/
GSList *messages;
/**
* The number of messages in #messages.
*/
unsigned num_messages;
};
extern unsigned int client_max_connections;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

96
src/client_message.c Normal file

@@ -0,0 +1,96 @@
/*
* Copyright (C) 2003-2011 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 "client_message.h"
#include <assert.h>
#include <glib.h>
G_GNUC_PURE
static bool
valid_channel_char(const char ch)
{
return g_ascii_isalnum(ch) ||
ch == '_' || ch == '-' || ch == '.' || ch == ':';
}
bool
client_message_valid_channel_name(const char *name)
{
do {
if (!valid_channel_char(*name))
return false;
} while (*++name != 0);
return true;
}
void
client_message_init_null(struct client_message *msg)
{
assert(msg != NULL);
msg->channel = NULL;
msg->message = NULL;
}
void
client_message_init(struct client_message *msg,
const char *channel, const char *message)
{
assert(msg != NULL);
msg->channel = g_strdup(channel);
msg->message = g_strdup(message);
}
void
client_message_copy(struct client_message *dest,
const struct client_message *src)
{
assert(dest != NULL);
assert(src != NULL);
assert(client_message_defined(src));
client_message_init(dest, src->channel, src->message);
}
struct client_message *
client_message_dup(const struct client_message *src)
{
struct client_message *dest = g_slice_new(struct client_message);
client_message_copy(dest, src);
return dest;
}
void
client_message_deinit(struct client_message *msg)
{
assert(msg != NULL);
g_free(msg->channel);
g_free(msg->message);
}
void
client_message_free(struct client_message *msg)
{
client_message_deinit(msg);
g_slice_free(struct client_message, msg);
}

72
src/client_message.h Normal file

@@ -0,0 +1,72 @@
/*
* Copyright (C) 2003-2011 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_CLIENT_MESSAGE_H
#define MPD_CLIENT_MESSAGE_H
#include <assert.h>
#include <stdbool.h>
#include <stddef.h>
#include <glib.h>
/**
* A client-to-client message.
*/
struct client_message {
char *channel;
char *message;
};
G_GNUC_PURE
bool
client_message_valid_channel_name(const char *name);
G_GNUC_PURE
static inline bool
client_message_defined(const struct client_message *msg)
{
assert(msg != NULL);
assert((msg->channel == NULL) == (msg->message == NULL));
return msg->channel != NULL;
}
void
client_message_init_null(struct client_message *msg);
void
client_message_init(struct client_message *msg,
const char *channel, const char *message);
void
client_message_copy(struct client_message *dest,
const struct client_message *src);
G_GNUC_MALLOC
struct client_message *
client_message_dup(const struct client_message *src);
void
client_message_deinit(struct client_message *msg);
void
client_message_free(struct client_message *msg);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,9 +19,11 @@
#include "config.h"
#include "client_internal.h"
#include "fd_util.h"
#include "fifo_buffer.h"
#include "socket_util.h"
#include "resolver.h"
#include "permission.h"
#include "glib_socket.h"
#include <assert.h>
#include <sys/types.h>
@@ -41,12 +43,15 @@
static const char GREETING[] = "OK MPD " PROTOCOL_VERSION "\n";
void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
void
client_new(struct player_control *player_control,
int fd, const struct sockaddr *sa, size_t sa_length, int uid)
{
static unsigned int next_client_num;
struct client *client;
char *remote;
assert(player_control != NULL);
assert(fd >= 0);
#ifdef HAVE_LIBWRAP
@@ -66,7 +71,7 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
progname, hostaddr);
g_free(hostaddr);
close(fd);
close_socket(fd);
return;
}
@@ -76,17 +81,14 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
if (client_list_is_full()) {
g_warning("Max Connections Reached!");
close(fd);
close_socket(fd);
return;
}
client = g_new0(struct client, 1);
client->player_control = player_control;
#ifndef G_OS_WIN32
client->channel = g_io_channel_unix_new(fd);
#else
client->channel = g_io_channel_win32_new_socket(fd);
#endif
client->channel = g_io_channel_new_socket(fd);
/* GLib is responsible for closing the file descriptor */
g_io_channel_set_close_on_unref(client->channel, true);
/* NULL encoding means the stream is binary safe; the MPD
@@ -117,6 +119,10 @@ void client_new(int fd, const struct sockaddr *sa, size_t sa_length, int uid)
client->send_buf_used = 0;
client->subscriptions = NULL;
client->messages = NULL;
client->num_messages = 0;
(void)send(fd, GREETING, sizeof(GREETING) - 1, 0);
client_list_add(client);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

123
src/client_subscribe.c Normal file

@@ -0,0 +1,123 @@
/*
* Copyright (C) 2003-2011 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 "client_subscribe.h"
#include "client_internal.h"
#include "client_idle.h"
#include "idle.h"
#include <string.h>
G_GNUC_PURE
static GSList *
client_find_subscription(const struct client *client, const char *channel)
{
for (GSList *i = client->subscriptions; i != NULL; i = g_slist_next(i))
if (strcmp((const char *)i->data, channel) == 0)
return i;
return NULL;
}
enum client_subscribe_result
client_subscribe(struct client *client, const char *channel)
{
assert(client != NULL);
assert(channel != NULL);
if (!client_message_valid_channel_name(channel))
return CLIENT_SUBSCRIBE_INVALID;
if (client_find_subscription(client, channel) != NULL)
return CLIENT_SUBSCRIBE_ALREADY;
if (client->num_subscriptions >= CLIENT_MAX_SUBSCRIPTIONS)
return CLIENT_SUBSCRIBE_FULL;
client->subscriptions = g_slist_prepend(client->subscriptions,
g_strdup(channel));
++client->num_subscriptions;
idle_add(IDLE_SUBSCRIPTION);
return CLIENT_SUBSCRIBE_OK;
}
bool
client_unsubscribe(struct client *client, const char *channel)
{
GSList *i = client_find_subscription(client, channel);
if (i == NULL)
return false;
assert(client->num_subscriptions > 0);
client->subscriptions = g_slist_remove(client->subscriptions, i->data);
--client->num_subscriptions;
idle_add(IDLE_SUBSCRIPTION);
assert((client->num_subscriptions == 0) ==
(client->subscriptions == NULL));
return true;
}
void
client_unsubscribe_all(struct client *client)
{
for (GSList *i = client->subscriptions; i != NULL; i = g_slist_next(i))
g_free(i->data);
g_slist_free(client->subscriptions);
client->subscriptions = NULL;
client->num_subscriptions = 0;
}
bool
client_push_message(struct client *client, const struct client_message *msg)
{
assert(client != NULL);
assert(msg != NULL);
assert(client_message_defined(msg));
if (client->num_messages >= CLIENT_MAX_MESSAGES ||
client_find_subscription(client, msg->channel) == NULL)
return false;
if (client->messages == NULL)
client_idle_add(client, IDLE_MESSAGE);
client->messages = g_slist_prepend(client->messages,
client_message_dup(msg));
++client->num_messages;
return true;
}
GSList *
client_read_messages(struct client *client)
{
GSList *messages = g_slist_reverse(client->messages);
client->messages = NULL;
client->num_messages = 0;
return messages;
}

59
src/client_subscribe.h Normal file

@@ -0,0 +1,59 @@
/*
* Copyright (C) 2003-2011 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_CLIENT_SUBSCRIBE_H
#define MPD_CLIENT_SUBSCRIBE_H
#include <stdbool.h>
#include <glib.h>
struct client;
struct client_message;
enum client_subscribe_result {
/** success */
CLIENT_SUBSCRIBE_OK,
/** invalid channel name */
CLIENT_SUBSCRIBE_INVALID,
/** already subscribed to this channel */
CLIENT_SUBSCRIBE_ALREADY,
/** too many subscriptions */
CLIENT_SUBSCRIBE_FULL,
};
enum client_subscribe_result
client_subscribe(struct client *client, const char *channel);
bool
client_unsubscribe(struct client *client, const char *channel);
void
client_unsubscribe_all(struct client *client);
bool
client_push_message(struct client *client, const struct client_message *msg);
G_GNUC_MALLOC
GSList *
client_read_messages(struct client *client);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

95
src/clock.c Normal file

@@ -0,0 +1,95 @@
/*
* Copyright (C) 2003-2012 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 "clock.h"
#ifdef WIN32
#include <windows.h>
#elif defined(__APPLE__)
#include <mach/mach_time.h>
#else
#include <time.h>
#endif
unsigned
monotonic_clock_ms(void)
{
#ifdef WIN32
return GetTickCount();
#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */
static mach_timebase_info_data_t base;
if (base.denom == 0)
(void)mach_timebase_info(&base);
return (unsigned)((mach_absolute_time() * base.numer)
/ (1000000 * base.denom));
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return ts.tv_sec * 1000 + ts.tv_nsec / 1000000;
#else
/* we have no monotonic clock, fall back to gettimeofday() */
struct timeval tv;
gettimeofday(&tv, 0);
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
#endif
}
uint64_t
monotonic_clock_us(void)
{
#ifdef WIN32
LARGE_INTEGER l_value, l_frequency;
if (!QueryPerformanceCounter(&l_value) ||
!QueryPerformanceFrequency(&l_frequency))
return 0;
uint64_t value = l_value.QuadPart;
uint64_t frequency = l_frequency.QuadPart;
if (frequency > 1000000) {
value *= 10000;
value /= frequency / 100;
} else if (frequency < 1000000) {
value *= 10000;
value /= frequency;
value *= 100;
}
return value;
#elif defined(__APPLE__) /* OS X does not define CLOCK_MONOTONIC */
static mach_timebase_info_data_t base;
if (base.denom == 0)
(void)mach_timebase_info(&base);
return ((uint64_t)mach_absolute_time() * (uint64_t)base.numer)
/ (1000 * (uint64_t)base.denom);
#elif defined(CLOCK_MONOTONIC)
struct timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
return (uint64_t)ts.tv_sec * 1000000 + (uint64_t)(ts.tv_nsec / 1000);
#else
/* we have no monotonic clock, fall back to gettimeofday() */
struct timeval tv;
gettimeofday(&tv, 0);
return (uint64_t)tv.tv_sec * 1000 + (uint64_t)(tv.tv_usec) / 1000(;
#endif
}

41
src/clock.h Normal file

@@ -0,0 +1,41 @@
/*
* Copyright (C) 2003-2012 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_CLOCK_H
#define MPD_CLOCK_H
#include <glib.h>
#include <stdint.h>
/**
* Returns the value of a monotonic clock in milliseconds.
*/
G_GNUC_PURE
unsigned
monotonic_clock_ms(void);
/**
* Returns the value of a monotonic clock in microseconds.
*/
G_GNUC_PURE
uint64_t
monotonic_clock_us(void);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -25,15 +25,23 @@
#include "decoder_list.h"
#include "decoder_plugin.h"
#include "output_list.h"
#include "output_plugin.h"
#include "input_registry.h"
#include "input_plugin.h"
#include "playlist_list.h"
#include "playlist_plugin.h"
#include "ls.h"
#include "mpd_error.h"
#include "glib_compat.h"
#ifdef ENABLE_ENCODER
#include "encoder_list.h"
#include "encoder_plugin.h"
#endif
#ifdef ENABLE_ARCHIVE
#include "archive_list.h"
#include "archive_plugin.h"
#endif
#include <glib.h>
@@ -54,59 +62,70 @@ cmdline_quark(void)
return g_quark_from_static_string("cmdline");
}
static void
print_all_decoders(FILE *fp)
{
for (unsigned i = 0; decoder_plugins[i] != NULL; ++i) {
const struct decoder_plugin *plugin = decoder_plugins[i];
const char *const*suffixes;
fprintf(fp, "[%s]", plugin->name);
for (suffixes = plugin->suffixes;
suffixes != NULL && *suffixes != NULL;
++suffixes) {
fprintf(fp, " %s", *suffixes);
}
fprintf(fp, "\n");
}
}
G_GNUC_NORETURN
static void version(void)
{
puts(PACKAGE " (MPD: Music Player Daemon) " VERSION " \n"
"\n"
"Copyright (C) 2003-2007 Warren Dukes <warren.dukes@gmail.com>\n"
"Copyright (C) 2008-2010 Max Kellermann <max@duempel.org>\n"
"Copyright (C) 2008-2012 Max Kellermann <max@duempel.org>\n"
"This is free software; see the source for copying conditions. There is NO\n"
"warranty; not even MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
"\n"
"Supported decoders:\n");
"Decoders plugins:");
print_all_decoders(stdout);
decoder_plugins_for_each(plugin) {
printf(" [%s]", plugin->name);
const char *const*suffixes = plugin->suffixes;
if (suffixes != NULL)
for (; *suffixes != NULL; ++suffixes)
printf(" %s", *suffixes);
puts("");
}
puts("\n"
"Supported outputs:\n");
audio_output_plugin_print_all_types(stdout);
"Output plugins:");
audio_output_plugins_for_each(plugin)
printf(" %s", plugin->name);
puts("");
#ifdef ENABLE_ENCODER
puts("\n"
"Supported encoders:\n");
encoder_plugin_print_all_types(stdout);
"Encoder plugins:");
encoder_plugins_for_each(plugin)
printf(" %s", plugin->name);
puts("");
#endif
#ifdef ENABLE_ARCHIVE
puts("\n"
"Supported archives:\n");
archive_plugin_init_all();
archive_plugin_print_all_suffixes(stdout);
"Archive plugins:");
archive_plugins_for_each(plugin) {
printf(" [%s]", plugin->name);
const char *const*suffixes = plugin->suffixes;
if (suffixes != NULL)
for (; *suffixes != NULL; ++suffixes)
printf(" %s", *suffixes);
puts("");
}
#endif
puts("\n"
"Supported protocols:\n");
"Input plugins:");
input_plugins_for_each(plugin)
printf(" %s", plugin->name);
puts("\n\n"
"Playlist plugins:");
playlist_plugins_for_each(plugin)
printf(" %s", plugin->name);
puts("\n\n"
"Protocols:");
print_supported_uri_schemes_to_fp(stdout);
exit(EXIT_SUCCESS);
@@ -194,8 +213,6 @@ parse_cmdline(int argc, char **argv, struct options *options,
if(g_file_test(system_path,
G_FILE_TEST_IS_REGULAR)) {
ret = config_read_file(system_path,error_r);
g_free(system_path);
g_free(&system_config_dirs);
break;
}
++i;;

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

File diff suppressed because it is too large Load Diff

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,9 +20,9 @@
#include "config.h"
#include "conf.h"
#include "utils.h"
#include "string_util.h"
#include "tokenizer.h"
#include "path.h"
#include "glib_compat.h"
#include "mpd_error.h"
#include <glib.h>
@@ -58,6 +58,7 @@ static struct config_entry config_entries[] = {
{ .name = CONF_LOG_FILE, false, false },
{ .name = CONF_PID_FILE, false, false },
{ .name = CONF_STATE_FILE, false, false },
{ .name = "restore_paused", false, false },
{ .name = CONF_USER, false, false },
{ .name = CONF_GROUP, false, false },
{ .name = CONF_BIND_TO_ADDRESS, true, false },
@@ -97,6 +98,9 @@ static struct config_entry config_entries[] = {
{ .name = CONF_PLAYLIST_PLUGIN, true, true },
{ .name = CONF_AUTO_UPDATE, false, false },
{ .name = CONF_AUTO_UPDATE_DEPTH, false, false },
{ .name = CONF_DESPOTIFY_USER, false, false },
{ .name = CONF_DESPOTIFY_PASSWORD, false, false},
{ .name = CONF_DESPOTIFY_HIGH_BITRATE, false, false },
{ .name = "filter", true, true },
};
@@ -138,7 +142,7 @@ config_new_param(const char *value, int line)
return ret;
}
static void
void
config_param_free(struct config_param *param)
{
g_free(param->value);
@@ -218,20 +222,13 @@ void config_global_check(void)
}
}
bool
void
config_add_block_param(struct config_param * param, const char *name,
const char *value, int line, GError **error_r)
const char *value, int line)
{
struct block_param *bp;
bp = config_get_block_param(param, name);
if (bp != NULL) {
g_set_error(error_r, config_quark(), 0,
"\"%s\" first defined on line %i, and "
"redefined on line %i\n", name,
bp->line, line);
return false;
}
assert(config_get_block_param(param, name) == NULL);
param->num_block_params++;
@@ -245,7 +242,46 @@ config_add_block_param(struct config_param * param, const char *name,
bp->value = g_strdup(value);
bp->line = line;
bp->used = false;
}
static bool
config_read_name_value(struct config_param *param, char *input, unsigned line,
GError **error_r)
{
const char *name = tokenizer_next_word(&input, error_r);
if (name == NULL) {
assert(*input != 0);
return false;
}
const char *value = tokenizer_next_string(&input, error_r);
if (value == NULL) {
if (*input == 0) {
assert(error_r == NULL || *error_r == NULL);
g_set_error(error_r, config_quark(), 0,
"Value missing");
} else {
assert(error_r == NULL || *error_r != NULL);
}
return false;
}
if (*input != 0 && *input != CONF_COMMENT) {
g_set_error(error_r, config_quark(), 0,
"Unknown tokens after value");
return false;
}
const struct block_param *bp = config_get_block_param(param, name);
if (bp != NULL) {
g_set_error(error_r, config_quark(), 0,
"\"%s\" is duplicate, first defined on line %i",
name, bp->line);
return false;
}
config_add_block_param(param, name, value, line);
return true;
}
@@ -254,11 +290,9 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
{
struct config_param *ret = config_new_param(NULL, *count);
GError *error = NULL;
bool success;
while (true) {
char *line;
const char *name, *value;
line = fgets(string, MAX_STRING_SIZE, fp);
if (line == NULL) {
@@ -269,7 +303,7 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
}
(*count)++;
line = g_strchug(line);
line = strchug_fast(line);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -277,7 +311,7 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
/* end of this block; return from the function
(and from this "while" loop) */
line = g_strchug(line + 1);
line = strchug_fast(line + 1);
if (*line != 0 && *line != CONF_COMMENT) {
config_param_free(ret);
g_set_error(error_r, config_quark(), 0,
@@ -291,42 +325,13 @@ config_read_block(FILE *fp, int *count, char *string, GError **error_r)
/* parse name and value */
name = tokenizer_next_word(&line, &error);
if (name == NULL) {
if (!config_read_name_value(ret, line, *count, &error)) {
assert(*line != 0);
config_param_free(ret);
g_propagate_prefixed_error(error_r, error,
"line %i: ", *count);
return NULL;
}
value = tokenizer_next_string(&line, &error);
if (value == NULL) {
config_param_free(ret);
if (*line == 0)
g_set_error(error_r, config_quark(), 0,
"line %i: Value missing", *count);
else
g_propagate_prefixed_error(error_r, error,
"line %i: ",
*count);
return NULL;
}
if (*line != 0 && *line != CONF_COMMENT) {
config_param_free(ret);
g_set_error(error_r, config_quark(), 0,
"line %i: Unknown tokens after value",
*count);
return NULL;
}
success = config_add_block_param(ret, name, value, *count,
error_r);
if (!success) {
config_param_free(ret);
return false;
}
}
}
@@ -344,7 +349,7 @@ config_read_file(const char *file, GError **error_r)
if (!(fp = fopen(file, "r"))) {
g_set_error(error_r, config_quark(), errno,
"Failed to open %s: %s",
file, strerror(errno));
file, g_strerror(errno));
return false;
}
@@ -355,7 +360,7 @@ config_read_file(const char *file, GError **error_r)
count++;
line = g_strchug(string);
line = strchug_fast(string);
if (*line == 0 || *line == CONF_COMMENT)
continue;
@@ -367,6 +372,7 @@ config_read_file(const char *file, GError **error_r)
assert(*line != 0);
g_propagate_prefixed_error(error_r, error,
"line %i: ", count);
fclose(fp);
return false;
}
@@ -378,6 +384,7 @@ config_read_file(const char *file, GError **error_r)
g_set_error(error_r, config_quark(), 0,
"unrecognized parameter in config file at "
"line %i: %s\n", count, name);
fclose(fp);
return false;
}
@@ -387,6 +394,7 @@ config_read_file(const char *file, GError **error_r)
"config parameter \"%s\" is first defined "
"on line %i and redefined on line %i\n",
name, param->line, count);
fclose(fp);
return false;
}
@@ -398,20 +406,24 @@ config_read_file(const char *file, GError **error_r)
if (*line != '{') {
g_set_error(error_r, config_quark(), 0,
"line %i: '{' expected", count);
fclose(fp);
return false;
}
line = g_strchug(line + 1);
line = strchug_fast(line + 1);
if (*line != 0 && *line != CONF_COMMENT) {
g_set_error(error_r, config_quark(), 0,
"line %i: Unknown tokens after '{'",
count);
fclose(fp);
return false;
}
param = config_read_block(fp, &count, string, error_r);
if (param == NULL)
if (param == NULL) {
fclose(fp);
return false;
}
} else {
/* a string value */
@@ -428,6 +440,7 @@ config_read_file(const char *file, GError **error_r)
g_error_free(error);
}
fclose(fp);
return false;
}
@@ -435,6 +448,7 @@ config_read_file(const char *file, GError **error_r)
g_set_error(error_r, config_quark(), 0,
"line %i: Unknown tokens after value",
count);
fclose(fp);
return false;
}
@@ -448,7 +462,7 @@ config_read_file(const char *file, GError **error_r)
return true;
}
struct config_param *
const struct config_param *
config_get_next_param(const char *name, const struct config_param * last)
{
struct config_entry *entry;
@@ -488,22 +502,23 @@ config_get_string(const char *name, const char *default_value)
return param->value;
}
const char *
config_get_path(const char *name)
char *
config_dup_path(const char *name, GError **error_r)
{
struct config_param *param = config_get_param(name);
char *path;
assert(error_r != NULL);
assert(*error_r == NULL);
const struct config_param *param = config_get_param(name);
if (param == NULL)
return NULL;
path = parsePath(param->value);
if (path == NULL)
MPD_ERROR("error parsing \"%s\" at line %i\n",
name, param->line);
char *path = parsePath(param->value, error_r);
if (G_UNLIKELY(path == NULL))
g_prefix_error(error_r,
"Invalid path in \"%s\" at line %i: ",
name, param->line);
g_free(param->value);
return param->value = path;
return path;
}
unsigned
@@ -544,7 +559,7 @@ config_get_positive(const char *name, unsigned default_value)
return (unsigned)value;
}
struct block_param *
const struct block_param *
config_get_block_param(const struct config_param * param, const char *name)
{
if (param == NULL)
@@ -582,7 +597,7 @@ const char *
config_get_block_string(const struct config_param *param, const char *name,
const char *default_value)
{
struct block_param *bp = config_get_block_param(param, name);
const struct block_param *bp = config_get_block_param(param, name);
if (bp == NULL)
return default_value;
@@ -590,11 +605,31 @@ config_get_block_string(const struct config_param *param, const char *name,
return bp->value;
}
char *
config_dup_block_path(const struct config_param *param, const char *name,
GError **error_r)
{
assert(error_r != NULL);
assert(*error_r == NULL);
const struct block_param *bp = config_get_block_param(param, name);
if (bp == NULL)
return NULL;
char *path = parsePath(bp->value, error_r);
if (G_UNLIKELY(path == NULL))
g_prefix_error(error_r,
"Invalid path in \"%s\" at line %i: ",
name, bp->line);
return path;
}
unsigned
config_get_block_unsigned(const struct config_param *param, const char *name,
unsigned default_value)
{
struct block_param *bp = config_get_block_param(param, name);
const struct block_param *bp = config_get_block_param(param, name);
long value;
char *endptr;
@@ -615,7 +650,7 @@ bool
config_get_block_bool(const struct config_param *param, const char *name,
bool default_value)
{
struct block_param *bp = config_get_block_param(param, name);
const struct block_param *bp = config_get_block_param(param, name);
bool success, value;
if (bp == NULL)

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -72,6 +72,9 @@
#define CONF_PLAYLIST_PLUGIN "playlist_plugin"
#define CONF_AUTO_UPDATE "auto_update"
#define CONF_AUTO_UPDATE_DEPTH "auto_update_depth"
#define CONF_DESPOTIFY_USER "despotify_user"
#define CONF_DESPOTIFY_PASSWORD "despotify_password"
#define CONF_DESPOTIFY_HIGH_BITRATE "despotify_high_bitrate"
#define DEFAULT_PLAYLIST_MAX_LENGTH (1024*16)
#define DEFAULT_PLAYLIST_SAVE_ABSOLUTE_PATHS false
@@ -108,6 +111,7 @@ struct config_param {
* A GQuark for GError instances, resulting from malformed
* configuration.
*/
G_GNUC_CONST
static inline GQuark
config_quark(void)
{
@@ -129,11 +133,11 @@ config_read_file(const char *file, GError **error_r);
/* don't free the returned value
set _last_ to NULL to get first entry */
G_GNUC_PURE
struct config_param *
const struct config_param *
config_get_next_param(const char *name, const struct config_param *last);
G_GNUC_PURE
static inline struct config_param *
static inline const struct config_param *
config_get_param(const char *name)
{
return config_get_next_param(name, NULL);
@@ -152,17 +156,15 @@ config_get_string(const char *name, const char *default_value);
/**
* Returns an optional configuration variable which contains an
* absolute path. If there is a tilde prefix, it is expanded. Aborts
* MPD if the path is not a valid absolute path.
* absolute path. If there is a tilde prefix, it is expanded.
* Returns NULL if the value is not present. If the path could not be
* parsed, returns NULL and sets the error.
*
* The return value must be freed with g_free().
*/
/* We lie here really. This function is not pure as it has side
effects -- it parse the value and creates new string freeing
previous one. However, because this works the very same way each
time (ie. from the outside it appears as if function had no side
effects) we should be in the clear declaring it pure. */
G_GNUC_PURE
const char *
config_get_path(const char *name);
G_GNUC_MALLOC
char *
config_dup_path(const char *name, GError **error_r);
G_GNUC_PURE
unsigned
@@ -173,7 +175,7 @@ unsigned
config_get_positive(const char *name, unsigned default_value);
G_GNUC_PURE
struct block_param *
const struct block_param *
config_get_block_param(const struct config_param *param, const char *name);
G_GNUC_PURE
@@ -184,6 +186,7 @@ const char *
config_get_block_string(const struct config_param *param, const char *name,
const char *default_value);
G_GNUC_MALLOC
static inline char *
config_dup_block_string(const struct config_param *param, const char *name,
const char *default_value)
@@ -191,6 +194,15 @@ config_dup_block_string(const struct config_param *param, const char *name,
return g_strdup(config_get_block_string(param, name, default_value));
}
/**
* Same as config_dup_path(), but looks up the setting in the
* specified block.
*/
G_GNUC_MALLOC
char *
config_dup_block_path(const struct config_param *param, const char *name,
GError **error_r);
G_GNUC_PURE
unsigned
config_get_block_unsigned(const struct config_param *param, const char *name,
@@ -201,11 +213,15 @@ bool
config_get_block_bool(const struct config_param *param, const char *name,
bool default_value);
G_GNUC_MALLOC
struct config_param *
config_new_param(const char *value, int line);
bool
void
config_param_free(struct config_param *param);
void
config_add_block_param(struct config_param * param, const char *name,
const char *value, int line, GError **error_r);
const char *value, int line);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,7 +19,6 @@
#include "config.h"
#include "crossfade.h"
#include "pcm_mix.h"
#include "chunk.h"
#include "audio_format.h"
#include "tag.h"

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

339
src/cue/cue_parser.c Normal file

@@ -0,0 +1,339 @@
/*
* Copyright (C) 2003-2011 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 "cue_parser.h"
#include "string_util.h"
#include "song.h"
#include "tag.h"
#include <assert.h>
#include <stdlib.h>
struct cue_parser {
enum {
/**
* Parsing the CUE header.
*/
HEADER,
/**
* Parsing a "FILE ... WAVE".
*/
WAVE,
/**
* Ignore everything until the next "FILE".
*/
IGNORE_FILE,
/**
* Parsing a "TRACK ... AUDIO".
*/
TRACK,
/**
* Ignore everything until the next "TRACK".
*/
IGNORE_TRACK,
} state;
struct tag *tag;
char *filename;
struct song *current, *previous, *finished;
bool last_updated;
};
struct cue_parser *
cue_parser_new(void)
{
struct cue_parser *parser = g_new(struct cue_parser, 1);
parser->state = HEADER;
parser->tag = tag_new();
parser->filename = NULL;
parser->current = NULL;
parser->previous = NULL;
parser->finished = NULL;
return parser;
}
void
cue_parser_free(struct cue_parser *parser)
{
tag_free(parser->tag);
g_free(parser->filename);
if (parser->current != NULL)
song_free(parser->current);
if (parser->finished != NULL)
song_free(parser->finished);
g_free(parser);
}
static const char *
cue_next_word(char *p, char **pp)
{
assert(p >= *pp);
assert(!g_ascii_isspace(*p));
const char *word = p;
while (*p != 0 && !g_ascii_isspace(*p))
++p;
*p = 0;
*pp = p + 1;
return word;
}
static const char *
cue_next_quoted(char *p, char **pp)
{
assert(p >= *pp);
assert(p[-1] == '"');
char *end = strchr(p, '"');
if (end == NULL) {
/* syntax error - ignore it silently */
*pp = p + strlen(p);
return p;
}
*end = 0;
*pp = end + 1;
return p;
}
static const char *
cue_next_token(char **pp)
{
char *p = strchug_fast(*pp);
if (*p == 0)
return NULL;
return cue_next_word(p, pp);
}
static const char *
cue_next_value(char **pp)
{
char *p = strchug_fast(*pp);
if (*p == 0)
return NULL;
if (*p == '"')
return cue_next_quoted(p + 1, pp);
else
return cue_next_word(p, pp);
}
static void
cue_add_tag(struct tag *tag, enum tag_type type, char *p)
{
const char *value = cue_next_value(&p);
if (value != NULL)
tag_add_item(tag, type, value);
}
static void
cue_parse_rem(char *p, struct tag *tag)
{
const char *type = cue_next_token(&p);
if (type == NULL)
return;
enum tag_type type2 = tag_name_parse_i(type);
if (type2 != TAG_NUM_OF_ITEM_TYPES)
cue_add_tag(tag, type2, p);
}
static struct tag *
cue_current_tag(struct cue_parser *parser)
{
if (parser->state == HEADER)
return parser->tag;
else if (parser->state == TRACK)
return parser->current->tag;
else
return NULL;
}
static int
cue_parse_position(const char *p)
{
char *endptr;
unsigned long minutes = strtoul(p, &endptr, 10);
if (endptr == p || *endptr != ':')
return -1;
p = endptr + 1;
unsigned long seconds = strtoul(p, &endptr, 10);
if (endptr == p || *endptr != ':')
return -1;
p = endptr + 1;
unsigned long frames = strtoul(p, &endptr, 10);
if (endptr == p || *endptr != 0)
return -1;
return minutes * 60000 + seconds * 1000 + frames * 1000 / 75;
}
static void
cue_parser_feed2(struct cue_parser *parser, char *p)
{
assert(parser != NULL);
assert(p != NULL);
const char *command = cue_next_token(&p);
if (command == NULL)
return;
if (strcmp(command, "REM") == 0) {
struct tag *tag = cue_current_tag(parser);
if (tag != NULL)
cue_parse_rem(p, tag);
} else if (strcmp(command, "PERFORMER") == 0) {
/* MPD knows a "performer" tag, but it is not a good
match for this CUE tag; from the Hydrogenaudio
Knowledgebase: "At top-level this will specify the
CD artist, while at track-level it specifies the
track artist." */
enum tag_type type = parser->state == TRACK
? TAG_ARTIST
: TAG_ALBUM_ARTIST;
struct tag *tag = cue_current_tag(parser);
if (tag != NULL)
cue_add_tag(tag, type, p);
} else if (strcmp(command, "TITLE") == 0) {
if (parser->state == HEADER)
cue_add_tag(parser->tag, TAG_ALBUM, p);
else if (parser->state == TRACK)
cue_add_tag(parser->current->tag, TAG_TITLE, p);
} else if (strcmp(command, "FILE") == 0) {
cue_parser_finish(parser);
const char *filename = cue_next_value(&p);
if (filename == NULL)
return;
const char *type = cue_next_token(&p);
if (type == NULL)
return;
if (strcmp(type, "WAVE") != 0 &&
strcmp(type, "MP3") != 0 &&
strcmp(type, "AIFF") != 0) {
parser->state = IGNORE_FILE;
return;
}
parser->state = WAVE;
g_free(parser->filename);
parser->filename = g_strdup(filename);
} else if (parser->state == IGNORE_FILE) {
return;
} else if (strcmp(command, "TRACK") == 0) {
cue_parser_finish(parser);
const char *nr = cue_next_token(&p);
if (nr == NULL)
return;
const char *type = cue_next_token(&p);
if (type == NULL)
return;
if (strcmp(type, "AUDIO") != 0) {
parser->state = IGNORE_TRACK;
return;
}
parser->state = TRACK;
parser->current = song_remote_new(parser->filename);
assert(parser->current->tag == NULL);
parser->current->tag = tag_dup(parser->tag);
tag_add_item(parser->current->tag, TAG_TRACK, nr);
parser->last_updated = false;
} else if (parser->state == IGNORE_TRACK) {
return;
} else if (parser->state == TRACK && strcmp(command, "INDEX") == 0) {
const char *nr = cue_next_token(&p);
if (nr == NULL)
return;
const char *position = cue_next_token(&p);
if (position == NULL)
return;
int position_ms = cue_parse_position(position);
if (position_ms < 0)
return;
if (!parser->last_updated && parser->previous != NULL &&
parser->previous->start_ms < (unsigned)position_ms) {
parser->last_updated = true;
parser->previous->end_ms = position_ms;
parser->previous->tag->time =
(parser->previous->end_ms - parser->previous->start_ms + 500) / 1000;
}
parser->current->start_ms = position_ms;
}
}
void
cue_parser_feed(struct cue_parser *parser, const char *line)
{
assert(parser != NULL);
assert(line != NULL);
char *allocated = g_strdup(line);
cue_parser_feed2(parser, allocated);
g_free(allocated);
}
void
cue_parser_finish(struct cue_parser *parser)
{
if (parser->finished != NULL)
song_free(parser->finished);
parser->finished = parser->previous;
parser->previous = parser->current;
parser->current = NULL;
}
struct song *
cue_parser_get(struct cue_parser *parser)
{
assert(parser != NULL);
struct song *song = parser->finished;
parser->finished = NULL;
return song;
}

58
src/cue/cue_parser.h Normal file

@@ -0,0 +1,58 @@
/*
* Copyright (C) 2003-2011 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_CUE_PARSER_H
#define MPD_CUE_PARSER_H
#include "check.h"
#include <stdbool.h>
struct cue_parser *
cue_parser_new(void);
void
cue_parser_free(struct cue_parser *parser);
/**
* Feed a text line from the CUE file into the parser. Call
* cue_parser_get() after this to see if a song has been finished.
*/
void
cue_parser_feed(struct cue_parser *parser, const char *line);
/**
* Tell the parser that the end of the file has been reached. Call
* cue_parser_get() after this to see if a song has been finished.
* This procedure must be done twice!
*/
void
cue_parser_finish(struct cue_parser *parser);
/**
* Check if a song was finished by the last cue_parser_feed() or
* cue_parser_finish() call.
*
* @return a song object that must be freed by the caller, or NULL if
* no song was finished at this time
*/
struct song *
cue_parser_get(struct cue_parser *parser);
#endif

@@ -1,235 +0,0 @@
#include "config.h"
#include "cue_tag.h"
#include "tag.h"
#include <libcue/libcue.h>
#include <assert.h>
static struct tag *
cue_tag_cd(struct Cdtext *cdtext, struct Rem *rem)
{
struct tag *tag;
char *tmp;
assert(cdtext != NULL);
tag = tag_new();
tag_begin_add(tag);
/* TAG_ALBUM_ARTIST */
if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL)
tag_add_item(tag, TAG_ALBUM_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL)
tag_add_item(tag, TAG_ALBUM_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL)
tag_add_item(tag, TAG_ALBUM_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL)
tag_add_item(tag, TAG_ALBUM_ARTIST, tmp);
/* TAG_ARTIST */
if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
/* TAG_PERFORMER */
if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL)
tag_add_item(tag, TAG_PERFORMER, tmp);
/* TAG_COMPOSER */
if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL)
tag_add_item(tag, TAG_COMPOSER, tmp);
/* TAG_ALBUM */
if ((tmp = cdtext_get(PTI_TITLE, cdtext)) != NULL)
tag_add_item(tag, TAG_ALBUM, tmp);
/* TAG_GENRE */
if ((tmp = cdtext_get(PTI_GENRE, cdtext)) != NULL)
tag_add_item(tag, TAG_GENRE, tmp);
/* TAG_DATE */
if ((tmp = rem_get(REM_DATE, rem)) != NULL)
tag_add_item(tag, TAG_DATE, tmp);
/* TAG_COMMENT */
if ((tmp = cdtext_get(PTI_MESSAGE, cdtext)) != NULL)
tag_add_item(tag, TAG_COMMENT, tmp);
/* TAG_DISC */
if ((tmp = cdtext_get(PTI_DISC_ID, cdtext)) != NULL)
tag_add_item(tag, TAG_DISC, tmp);
/* stream name, usually empty
* tag_add_item(tag, TAG_NAME,);
*/
/* REM MUSICBRAINZ entry?
tag_add_item(tag, TAG_MUSICBRAINZ_ARTISTID,);
tag_add_item(tag, TAG_MUSICBRAINZ_ALBUMID,);
tag_add_item(tag, TAG_MUSICBRAINZ_ALBUMARTISTID,);
tag_add_item(tag, TAG_MUSICBRAINZ_TRACKID,);
*/
tag_end_add(tag);
if (tag_is_empty(tag)) {
tag_free(tag);
return NULL;
}
return tag;
}
static struct tag *
cue_tag_track(struct Cdtext *cdtext, struct Rem *rem)
{
struct tag *tag;
char *tmp;
assert(cdtext != NULL);
tag = tag_new();
tag_begin_add(tag);
/* TAG_ARTIST */
if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_SONGWRITER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
else if ((tmp = cdtext_get(PTI_ARRANGER, cdtext)) != NULL)
tag_add_item(tag, TAG_ARTIST, tmp);
/* TAG_TITLE */
if ((tmp = cdtext_get(PTI_TITLE, cdtext)) != NULL)
tag_add_item(tag, TAG_TITLE, tmp);
/* TAG_GENRE */
if ((tmp = cdtext_get(PTI_GENRE, cdtext)) != NULL)
tag_add_item(tag, TAG_GENRE, tmp);
/* TAG_DATE */
if ((tmp = rem_get(REM_DATE, rem)) != NULL)
tag_add_item(tag, TAG_DATE, tmp);
/* TAG_COMPOSER */
if ((tmp = cdtext_get(PTI_COMPOSER, cdtext)) != NULL)
tag_add_item(tag, TAG_COMPOSER, tmp);
/* TAG_PERFORMER */
if ((tmp = cdtext_get(PTI_PERFORMER, cdtext)) != NULL)
tag_add_item(tag, TAG_PERFORMER, tmp);
/* TAG_COMMENT */
if ((tmp = cdtext_get(PTI_MESSAGE, cdtext)) != NULL)
tag_add_item(tag, TAG_COMMENT, tmp);
/* TAG_DISC */
if ((tmp = cdtext_get(PTI_DISC_ID, cdtext)) != NULL)
tag_add_item(tag, TAG_DISC, tmp);
tag_end_add(tag);
if (tag_is_empty(tag)) {
tag_free(tag);
return NULL;
}
return tag;
}
struct tag *
cue_tag(struct Cd *cd, unsigned tnum)
{
struct tag *cd_tag, *track_tag, *tag;
struct Track *track;
assert(cd != NULL);
track = cd_get_track(cd, tnum);
if (track == NULL)
return NULL;
/* tag from CDtext info */
cd_tag = cue_tag_cd(cd_get_cdtext(cd), cd_get_rem(cd));
/* tag from TRACKtext info */
track_tag = cue_tag_track(track_get_cdtext(track),
track_get_rem(track));
tag = tag_merge_replace(cd_tag, track_tag);
if (tag == NULL)
return NULL;
tag->time = track_get_length(track)
- track_get_index(track, 1)
+ track_get_zero_pre(track);
track = cd_get_track(cd, tnum + 1);
if (track != NULL)
tag->time += track_get_index(track, 1)
- track_get_zero_pre(track);
/* libcue returns the track duration in frames, and there are
75 frames per second; this formula rounds down */
tag->time = tag->time / 75;
return tag;
}
struct tag *
cue_tag_file(FILE *fp, unsigned tnum)
{
struct Cd *cd;
struct tag *tag;
assert(fp != NULL);
if (tnum > 256)
return NULL;
cd = cue_parse_file(fp);
if (cd == NULL)
return NULL;
tag = cue_tag(cd, tnum);
cd_delete(cd);
return tag;
}
struct tag *
cue_tag_string(const char *str, unsigned tnum)
{
struct Cd *cd;
struct tag *tag;
assert(str != NULL);
if (tnum > 256)
return NULL;
cd = cue_parse_string(str);
if (cd == NULL)
return NULL;
tag = cue_tag(cd, tnum);
cd_delete(cd);
return tag;
}

@@ -1,23 +0,0 @@
#ifndef MPD_CUE_TAG_H
#define MPD_CUE_TAG_H
#include "check.h"
#ifdef HAVE_CUE /* libcue */
#include <stdio.h>
struct tag;
struct Cd;
struct tag *
cue_tag(struct Cd *cd, unsigned tnum);
struct tag *
cue_tag_file(FILE *file, unsigned tnum);
struct tag *
cue_tag_string(const char *str, unsigned tnum);
#endif /* libcue */
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -80,7 +80,7 @@ daemonize_kill(void)
ret = kill(pid, SIGTERM);
if (ret < 0)
MPD_ERROR("unable to kill proccess %i: %s",
MPD_ERROR("unable to kill process %i: %s",
pid, g_strerror(errno));
exit(EXIT_SUCCESS);

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -19,14 +19,16 @@
#include "config.h"
#include "database.h"
#include "db_error.h"
#include "db_save.h"
#include "db_selection.h"
#include "db_visitor.h"
#include "db_plugin.h"
#include "db/simple_db_plugin.h"
#include "directory.h"
#include "directory_save.h"
#include "song.h"
#include "path.h"
#include "stats.h"
#include "text_file.h"
#include "tag.h"
#include "tag_internal.h"
#include "conf.h"
#include "glib_compat.h"
#include <glib.h>
@@ -35,85 +37,64 @@
#include <unistd.h>
#include <assert.h>
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#undef G_LOG_DOMAIN
#define G_LOG_DOMAIN "database"
#define DIRECTORY_INFO_BEGIN "info_begin"
#define DIRECTORY_INFO_END "info_end"
#define DB_FORMAT_PREFIX "format: "
#define DIRECTORY_MPD_VERSION "mpd_version: "
#define DIRECTORY_FS_CHARSET "fs_charset: "
#define DB_TAG_PREFIX "tag: "
static struct db *db;
static bool db_is_open;
enum {
DB_FORMAT = 1,
};
static char *database_path;
static struct directory *music_root;
static time_t database_mtime;
/**
* The quark used for GError.domain.
*/
static inline GQuark
db_quark(void)
bool
db_init(const struct config_param *path, GError **error_r)
{
return g_quark_from_static_string("database");
}
assert(db == NULL);
assert(!db_is_open);
void
db_init(const char *path)
{
database_path = g_strdup(path);
if (path == NULL)
return true;
if (path != NULL)
music_root = directory_new("", NULL);
struct config_param *param = config_new_param("database", path->line);
config_add_block_param(param, "path", path->value, path->line);
db = db_plugin_new(&simple_db_plugin, param, error_r);
config_param_free(param);
return db != NULL;
}
void
db_finish(void)
{
assert((database_path == NULL) == (music_root == NULL));
if (db_is_open)
db_plugin_close(db);
if (music_root != NULL)
directory_free(music_root);
g_free(database_path);
}
void
db_clear(void)
{
assert(music_root != NULL);
directory_free(music_root);
music_root = directory_new("", NULL);
if (db != NULL)
db_plugin_free(db);
}
struct directory *
db_get_root(void)
{
assert(music_root != NULL);
assert(db != NULL);
return music_root;
return simple_db_get_root(db);
}
struct directory *
db_get_directory(const char *name)
{
if (music_root == NULL)
if (db == NULL)
return NULL;
struct directory *music_root = db_get_root();
if (name == NULL)
return music_root;
return directory_lookup_directory(music_root, name);
struct directory *directory =
directory_lookup_directory(music_root, name);
return directory;
}
struct song *
@@ -123,281 +104,67 @@ db_get_song(const char *file)
g_debug("get song: %s", file);
if (music_root == NULL)
if (db == NULL)
return NULL;
return directory_lookup_song(music_root, file);
}
int
db_walk(const char *name,
int (*forEachSong)(struct song *, void *),
int (*forEachDir)(struct directory *, void *), void *data)
{
struct directory *directory;
if (music_root == NULL)
return -1;
if ((directory = db_get_directory(name)) == NULL) {
struct song *song;
if ((song = db_get_song(name)) && forEachSong) {
return forEachSong(song, data);
}
return -1;
}
return directory_walk(directory, forEachSong, forEachDir, data);
return db_plugin_get_song(db, file, NULL);
}
bool
db_check(void)
db_visit(const struct db_selection *selection,
const struct db_visitor *visitor, void *ctx,
GError **error_r)
{
struct stat st;
assert(database_path != NULL);
/* Check if the file exists */
if (access(database_path, F_OK)) {
/* If the file doesn't exist, we can't check if we can write
* it, so we are going to try to get the directory path, and
* see if we can write a file in that */
char *dirPath = g_path_get_dirname(database_path);
/* Check that the parent part of the path is a directory */
if (stat(dirPath, &st) < 0) {
g_free(dirPath);
g_warning("Couldn't stat parent directory of db file "
"\"%s\": %s", database_path, strerror(errno));
return false;
}
if (!S_ISDIR(st.st_mode)) {
g_free(dirPath);
g_warning("Couldn't create db file \"%s\" because the "
"parent path is not a directory", database_path);
return false;
}
/* Check if we can write to the directory */
if (access(dirPath, R_OK | W_OK)) {
g_warning("Can't create db file in \"%s\": %s",
dirPath, strerror(errno));
g_free(dirPath);
return false;
}
g_free(dirPath);
return true;
}
/* Path exists, now check if it's a regular file */
if (stat(database_path, &st) < 0) {
g_warning("Couldn't stat db file \"%s\": %s",
database_path, strerror(errno));
if (db == NULL) {
g_set_error_literal(error_r, db_quark(), DB_DISABLED,
"No database");
return false;
}
if (!S_ISREG(st.st_mode)) {
g_warning("db file \"%s\" is not a regular file", database_path);
return false;
}
/* And check that we can write to it */
if (access(database_path, R_OK | W_OK)) {
g_warning("Can't open db file \"%s\" for reading/writing: %s",
database_path, strerror(errno));
return false;
}
return true;
return db_plugin_visit(db, selection, visitor, ctx, error_r);
}
bool
db_save(void)
db_walk(const char *uri,
const struct db_visitor *visitor, void *ctx,
GError **error_r)
{
FILE *fp;
struct stat st;
struct db_selection selection;
db_selection_init(&selection, uri, true);
assert(database_path != NULL);
assert(music_root != NULL);
return db_visit(&selection, visitor, ctx, error_r);
}
g_debug("removing empty directories from DB");
directory_prune_empty(music_root);
bool
db_save(GError **error_r)
{
assert(db != NULL);
assert(db_is_open);
g_debug("sorting DB");
directory_sort(music_root);
g_debug("writing DB");
fp = fopen(database_path, "w");
if (!fp) {
g_warning("unable to write to db file \"%s\": %s",
database_path, strerror(errno));
return false;
}
fprintf(fp, "%s\n", DIRECTORY_INFO_BEGIN);
fprintf(fp, DB_FORMAT_PREFIX "%u\n", DB_FORMAT);
fprintf(fp, "%s%s\n", DIRECTORY_MPD_VERSION, VERSION);
fprintf(fp, "%s%s\n", DIRECTORY_FS_CHARSET, path_get_fs_charset());
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i)
if (!ignore_tag_items[i])
fprintf(fp, DB_TAG_PREFIX "%s\n", tag_item_names[i]);
fprintf(fp, "%s\n", DIRECTORY_INFO_END);
directory_save(fp, music_root);
if (ferror(fp)) {
g_warning("Failed to write to database file: %s",
strerror(errno));
fclose(fp);
return false;
}
fclose(fp);
if (stat(database_path, &st) == 0)
database_mtime = st.st_mtime;
return true;
return simple_db_save(db, error_r);
}
bool
db_load(GError **error)
{
FILE *fp = NULL;
struct stat st;
GString *buffer = g_string_sized_new(1024);
char *line;
int format = 0;
bool found_charset = false, found_version = false;
bool success;
bool tags[TAG_NUM_OF_ITEM_TYPES];
assert(db != NULL);
assert(!db_is_open);
assert(database_path != NULL);
assert(music_root != NULL);
fp = fopen(database_path, "r");
if (fp == NULL) {
g_set_error(error, db_quark(), errno,
"Failed to open database file \"%s\": %s",
database_path, strerror(errno));
g_string_free(buffer, true);
if (!db_plugin_open(db, error))
return false;
}
/* get initial info */
line = read_text_line(fp, buffer);
if (line == NULL || strcmp(DIRECTORY_INFO_BEGIN, line) != 0) {
fclose(fp);
g_set_error(error, db_quark(), 0, "Database corrupted");
g_string_free(buffer, true);
return false;
}
memset(tags, false, sizeof(tags));
while ((line = read_text_line(fp, buffer)) != NULL &&
strcmp(line, DIRECTORY_INFO_END) != 0) {
if (g_str_has_prefix(line, DB_FORMAT_PREFIX)) {
format = atoi(line + sizeof(DB_FORMAT_PREFIX) - 1);
} else if (g_str_has_prefix(line, DIRECTORY_MPD_VERSION)) {
if (found_version) {
fclose(fp);
g_set_error(error, db_quark(), 0,
"Duplicate version line");
g_string_free(buffer, true);
return false;
}
found_version = true;
} else if (g_str_has_prefix(line, DIRECTORY_FS_CHARSET)) {
const char *new_charset, *old_charset;
if (found_charset) {
fclose(fp);
g_set_error(error, db_quark(), 0,
"Duplicate charset line");
g_string_free(buffer, true);
return false;
}
found_charset = true;
new_charset = line + sizeof(DIRECTORY_FS_CHARSET) - 1;
old_charset = path_get_fs_charset();
if (old_charset != NULL
&& strcmp(new_charset, old_charset)) {
fclose(fp);
g_set_error(error, db_quark(), 0,
"Existing database has charset "
"\"%s\" instead of \"%s\"; "
"discarding database file",
new_charset, old_charset);
g_string_free(buffer, true);
return false;
}
} else if (g_str_has_prefix(line, DB_TAG_PREFIX)) {
const char *name = line + sizeof(DB_TAG_PREFIX) - 1;
enum tag_type tag = tag_name_parse(name);
if (tag == TAG_NUM_OF_ITEM_TYPES) {
g_set_error(error, db_quark(), 0,
"Unrecognized tag '%s', "
"discarding database file",
name);
return false;
}
tags[tag] = true;
} else {
fclose(fp);
g_set_error(error, db_quark(), 0,
"Malformed line: %s", line);
g_string_free(buffer, true);
return false;
}
}
if (format != DB_FORMAT) {
g_set_error(error, db_quark(), 0,
"Database format mismatch, "
"discarding database file");
return false;
}
for (unsigned i = 0; i < TAG_NUM_OF_ITEM_TYPES; ++i) {
if (!ignore_tag_items[i] && !tags[i]) {
g_set_error(error, db_quark(), 0,
"Tag list mismatch, "
"discarding database file");
return false;
}
}
g_debug("reading DB");
success = directory_load(fp, music_root, buffer, error);
g_string_free(buffer, true);
fclose(fp);
if (!success)
return false;
db_is_open = true;
stats_update();
if (stat(database_path, &st) == 0)
database_mtime = st.st_mtime;
return true;
}
time_t
db_get_mtime(void)
{
return database_mtime;
assert(db != NULL);
assert(db_is_open);
return simple_db_get_mtime(db);
}

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,62 +20,76 @@
#ifndef MPD_DATABASE_H
#define MPD_DATABASE_H
#include "gcc.h"
#include <glib.h>
#include <sys/time.h>
#include <stdbool.h>
struct config_param;
struct directory;
struct db_selection;
struct db_visitor;
/**
* Initialize the database library.
*
* @param path the absolute path of the database file
*/
void
db_init(const char *path);
bool
db_init(const struct config_param *path, GError **error_r);
void
db_finish(void);
/**
* Clear the database.
*/
void
db_clear(void);
/**
* Returns the root directory object. Returns NULL if there is no
* configured music directory.
*/
G_GNUC_PURE
struct directory *
db_get_root(void);
/**
* Caller must lock the #db_mutex.
*/
gcc_nonnull(1)
G_GNUC_PURE
struct directory *
db_get_directory(const char *name);
gcc_nonnull(1)
G_GNUC_PURE
struct song *
db_get_song(const char *file);
int db_walk(const char *name,
int (*forEachSong)(struct song *, void *),
int (*forEachDir)(struct directory *, void *), void *data);
gcc_nonnull(1,2)
bool
db_visit(const struct db_selection *selection,
const struct db_visitor *visitor, void *ctx,
GError **error_r);
gcc_nonnull(1,2)
bool
db_walk(const char *uri,
const struct db_visitor *visitor, void *ctx,
GError **error_r);
bool
db_check(void);
bool
db_save(void);
db_save(GError **error_r);
bool
db_load(GError **error);
G_GNUC_PURE
time_t
db_get_mtime(void);
/**
* Returns true if there is a valid database file on the disk.
*/
G_GNUC_PURE
static inline bool
db_exists(void)
{

357
src/db/simple_db_plugin.c Normal file

@@ -0,0 +1,357 @@
/*
* Copyright (C) 2003-2011 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 "simple_db_plugin.h"
#include "db_internal.h"
#include "db_error.h"
#include "db_selection.h"
#include "db_visitor.h"
#include "db_save.h"
#include "db_lock.h"
#include "conf.h"
#include "directory.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <errno.h>
struct simple_db {
struct db base;
char *path;
struct directory *root;
time_t mtime;
};
G_GNUC_CONST
static inline GQuark
simple_db_quark(void)
{
return g_quark_from_static_string("simple_db");
}
G_GNUC_PURE
static const struct directory *
simple_db_lookup_directory(const struct simple_db *db, const char *uri)
{
assert(db != NULL);
assert(db->root != NULL);
assert(uri != NULL);
db_lock();
struct directory *directory =
directory_lookup_directory(db->root, uri);
db_unlock();
return directory;
}
static struct db *
simple_db_init(const struct config_param *param, GError **error_r)
{
struct simple_db *db = g_malloc(sizeof(*db));
db_base_init(&db->base, &simple_db_plugin);
GError *error = NULL;
db->path = config_dup_block_path(param, "path", &error);
if (db->path == NULL) {
g_free(db);
if (error != NULL)
g_propagate_error(error_r, error);
else
g_set_error(error_r, simple_db_quark(), 0,
"No \"path\" parameter specified");
return NULL;
}
return &db->base;
}
static void
simple_db_finish(struct db *_db)
{
struct simple_db *db = (struct simple_db *)_db;
g_free(db->path);
g_free(db);
}
static bool
simple_db_check(struct simple_db *db, GError **error_r)
{
assert(db != NULL);
assert(db->path != NULL);
/* Check if the file exists */
if (access(db->path, F_OK)) {
/* If the file doesn't exist, we can't check if we can write
* it, so we are going to try to get the directory path, and
* see if we can write a file in that */
char *dirPath = g_path_get_dirname(db->path);
/* Check that the parent part of the path is a directory */
struct stat st;
if (stat(dirPath, &st) < 0) {
g_free(dirPath);
g_set_error(error_r, simple_db_quark(), errno,
"Couldn't stat parent directory of db file "
"\"%s\": %s",
db->path, g_strerror(errno));
return false;
}
if (!S_ISDIR(st.st_mode)) {
g_free(dirPath);
g_set_error(error_r, simple_db_quark(), 0,
"Couldn't create db file \"%s\" because the "
"parent path is not a directory",
db->path);
return false;
}
/* Check if we can write to the directory */
if (access(dirPath, X_OK | W_OK)) {
g_set_error(error_r, simple_db_quark(), errno,
"Can't create db file in \"%s\": %s",
dirPath, g_strerror(errno));
g_free(dirPath);
return false;
}
g_free(dirPath);
return true;
}
/* Path exists, now check if it's a regular file */
struct stat st;
if (stat(db->path, &st) < 0) {
g_set_error(error_r, simple_db_quark(), errno,
"Couldn't stat db file \"%s\": %s",
db->path, g_strerror(errno));
return false;
}
if (!S_ISREG(st.st_mode)) {
g_set_error(error_r, simple_db_quark(), 0,
"db file \"%s\" is not a regular file",
db->path);
return false;
}
/* And check that we can write to it */
if (access(db->path, R_OK | W_OK)) {
g_set_error(error_r, simple_db_quark(), errno,
"Can't open db file \"%s\" for reading/writing: %s",
db->path, g_strerror(errno));
return false;
}
return true;
}
static bool
simple_db_load(struct simple_db *db, GError **error_r)
{
assert(db != NULL);
assert(db->path != NULL);
assert(db->root != NULL);
FILE *fp = fopen(db->path, "r");
if (fp == NULL) {
g_set_error(error_r, simple_db_quark(), errno,
"Failed to open database file \"%s\": %s",
db->path, g_strerror(errno));
return false;
}
if (!db_load_internal(fp, db->root, error_r)) {
fclose(fp);
return false;
}
fclose(fp);
struct stat st;
if (stat(db->path, &st) == 0)
db->mtime = st.st_mtime;
return true;
}
static bool
simple_db_open(struct db *_db, G_GNUC_UNUSED GError **error_r)
{
struct simple_db *db = (struct simple_db *)_db;
db->root = directory_new_root();
db->mtime = 0;
GError *error = NULL;
if (!simple_db_load(db, &error)) {
directory_free(db->root);
g_warning("Failed to load database: %s", error->message);
g_error_free(error);
if (!simple_db_check(db, error_r))
return false;
db->root = directory_new_root();
}
return true;
}
static void
simple_db_close(struct db *_db)
{
struct simple_db *db = (struct simple_db *)_db;
assert(db->root != NULL);
directory_free(db->root);
}
static struct song *
simple_db_get_song(struct db *_db, const char *uri, GError **error_r)
{
struct simple_db *db = (struct simple_db *)_db;
assert(db->root != NULL);
db_lock();
struct song *song = directory_lookup_song(db->root, uri);
db_unlock();
if (song == NULL)
g_set_error(error_r, db_quark(), DB_NOT_FOUND,
"No such song: %s", uri);
return song;
}
static bool
simple_db_visit(struct db *_db, const struct db_selection *selection,
const struct db_visitor *visitor, void *ctx,
GError **error_r)
{
const struct simple_db *db = (const struct simple_db *)_db;
const struct directory *directory =
simple_db_lookup_directory(db, selection->uri);
if (directory == NULL) {
struct song *song;
if (visitor->song != NULL &&
(song = simple_db_get_song(_db, selection->uri, NULL)) != NULL)
return visitor->song(song, ctx, error_r);
g_set_error(error_r, db_quark(), DB_NOT_FOUND,
"No such directory");
return false;
}
if (selection->recursive && visitor->directory != NULL &&
!visitor->directory(directory, ctx, error_r))
return false;
db_lock();
bool ret = directory_walk(directory, selection->recursive,
visitor, ctx, error_r);
db_unlock();
return ret;
}
const struct db_plugin simple_db_plugin = {
.name = "simple",
.init = simple_db_init,
.finish = simple_db_finish,
.open = simple_db_open,
.close = simple_db_close,
.get_song = simple_db_get_song,
.visit = simple_db_visit,
};
struct directory *
simple_db_get_root(struct db *_db)
{
struct simple_db *db = (struct simple_db *)_db;
assert(db != NULL);
assert(db->root != NULL);
return db->root;
}
bool
simple_db_save(struct db *_db, GError **error_r)
{
struct simple_db *db = (struct simple_db *)_db;
struct directory *music_root = db->root;
db_lock();
g_debug("removing empty directories from DB");
directory_prune_empty(music_root);
g_debug("sorting DB");
directory_sort(music_root);
db_unlock();
g_debug("writing DB");
FILE *fp = fopen(db->path, "w");
if (!fp) {
g_set_error(error_r, simple_db_quark(), errno,
"unable to write to db file \"%s\": %s",
db->path, g_strerror(errno));
return false;
}
db_save_internal(fp, music_root);
if (ferror(fp)) {
g_set_error(error_r, simple_db_quark(), errno,
"Failed to write to database file: %s",
g_strerror(errno));
fclose(fp);
return false;
}
fclose(fp);
struct stat st;
if (stat(db->path, &st) == 0)
db->mtime = st.st_mtime;
return true;
}
time_t
simple_db_get_mtime(const struct db *_db)
{
const struct simple_db *db = (const struct simple_db *)_db;
assert(db != NULL);
assert(db->root != NULL);
return db->mtime;
}

42
src/db/simple_db_plugin.h Normal file

@@ -0,0 +1,42 @@
/*
* Copyright (C) 2003-2011 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_SIMPLE_DB_PLUGIN_H
#define MPD_SIMPLE_DB_PLUGIN_H
#include <glib.h>
#include <stdbool.h>
#include <time.h>
extern const struct db_plugin simple_db_plugin;
struct db;
G_GNUC_PURE
struct directory *
simple_db_get_root(struct db *db);
bool
simple_db_save(struct db *db, GError **error_r);
G_GNUC_PURE
time_t
simple_db_get_mtime(const struct db *db);
#endif

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,311 +20,190 @@
#include "config.h"
#include "dbUtils.h"
#include "locate.h"
#include "directory.h"
#include "database.h"
#include "client.h"
#include "db_visitor.h"
#include "playlist.h"
#include "song.h"
#include "song_print.h"
#include "tag.h"
#include "strset.h"
#include "stored_playlist.h"
#include <glib.h>
#include <stdlib.h>
typedef struct _ListCommandItem {
int8_t tagType;
const struct locate_item_list *criteria;
} ListCommandItem;
typedef struct _SearchStats {
const struct locate_item_list *criteria;
int numberOfSongs;
unsigned long playTime;
} SearchStats;
static int
printDirectoryInDirectory(struct directory *directory, void *data)
static bool
add_to_queue_song(struct song *song, void *ctx, GError **error_r)
{
struct client *client = data;
struct player_control *pc = ctx;
if (!directory_is_root(directory))
client_printf(client, "directory: %s\n", directory_get_path(directory));
return 0;
}
static int
printSongInDirectory(struct song *song, G_GNUC_UNUSED void *data)
{
struct client *client = data;
song_print_uri(client, song);
return 0;
}
struct search_data {
struct client *client;
const struct locate_item_list *criteria;
};
static int
searchInDirectory(struct song *song, void *_data)
{
struct search_data *data = _data;
if (locate_song_search(song, data->criteria))
song_print_info(data->client, song);
return 0;
}
int
searchForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria)
{
int ret;
struct locate_item_list *new_list
= locate_item_list_casefold(criteria);
struct search_data data;
data.client = client;
data.criteria = new_list;
ret = db_walk(name, searchInDirectory, NULL, &data);
locate_item_list_free(new_list);
return ret;
}
static int
findInDirectory(struct song *song, void *_data)
{
struct search_data *data = _data;
if (locate_song_match(song, data->criteria))
song_print_info(data->client, song);
return 0;
}
int
findSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria)
{
struct search_data data;
data.client = client;
data.criteria = criteria;
return db_walk(name, findInDirectory, NULL, &data);
}
static void printSearchStats(struct client *client, SearchStats *stats)
{
client_printf(client, "songs: %i\n", stats->numberOfSongs);
client_printf(client, "playtime: %li\n", stats->playTime);
}
static int
searchStatsInDirectory(struct song *song, void *data)
{
SearchStats *stats = data;
if (locate_song_match(song, stats->criteria)) {
stats->numberOfSongs++;
stats->playTime += song_get_duration(song);
enum playlist_result result =
playlist_append_song(&g_playlist, pc, song, NULL);
if (result != PLAYLIST_RESULT_SUCCESS) {
g_set_error(error_r, playlist_quark(), result,
"Playlist error");
return false;
}
return 0;
return true;
}
int
searchStatsForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria)
static const struct db_visitor add_to_queue_visitor = {
.song = add_to_queue_song,
};
bool
addAllIn(struct player_control *pc, const char *uri, GError **error_r)
{
SearchStats stats;
int ret;
stats.criteria = criteria;
stats.numberOfSongs = 0;
stats.playTime = 0;
ret = db_walk(name, searchStatsInDirectory, NULL, &stats);
if (ret == 0)
printSearchStats(client, &stats);
return ret;
}
int printAllIn(struct client *client, const char *name)
{
return db_walk(name, printSongInDirectory,
printDirectoryInDirectory, client);
}
static int
directoryAddSongToPlaylist(struct song *song, G_GNUC_UNUSED void *data)
{
return playlist_append_song(&g_playlist, song, NULL);
return db_walk(uri, &add_to_queue_visitor, pc, error_r);
}
struct add_data {
const char *path;
};
static int
directoryAddSongToStoredPlaylist(struct song *song, void *_data)
static bool
add_to_spl_song(struct song *song, void *ctx, GError **error_r)
{
struct add_data *data = _data;
struct add_data *data = ctx;
if (spl_append_song(data->path, song) != 0)
return -1;
return 0;
if (!spl_append_song(data->path, song, error_r))
return false;
return true;
}
int addAllIn(const char *name)
{
return db_walk(name, directoryAddSongToPlaylist, NULL, NULL);
}
int addAllInToStoredPlaylist(const char *name, const char *utf8file)
{
struct add_data data = {
.path = utf8file,
};
return db_walk(name, directoryAddSongToStoredPlaylist, NULL, &data);
}
static int
findAddInDirectory(struct song *song, void *_data)
{
struct search_data *data = _data;
if (locate_song_match(song, data->criteria))
return directoryAddSongToPlaylist(song, data);
return 0;
}
int findAddIn(struct client *client, const char *name,
const struct locate_item_list *criteria)
{
struct search_data data;
data.client = client;
data.criteria = criteria;
return db_walk(name, findAddInDirectory, NULL, &data);
}
static int
directoryPrintSongInfo(struct song *song, void *data)
{
struct client *client = data;
song_print_info(client, song);
return 0;
}
int printInfoForAllIn(struct client *client, const char *name)
{
return db_walk(name, directoryPrintSongInfo,
printDirectoryInDirectory, client);
}
static ListCommandItem *
newListCommandItem(int tagType, const struct locate_item_list *criteria)
{
ListCommandItem *item = g_new(ListCommandItem, 1);
item->tagType = tagType;
item->criteria = criteria;
return item;
}
static void freeListCommandItem(ListCommandItem * item)
{
g_free(item);
}
static void
visitTag(struct client *client, struct strset *set,
struct song *song, enum tag_type tagType)
{
struct tag *tag = song->tag;
bool found = false;
if (tagType == LOCATE_TAG_FILE_TYPE) {
song_print_uri(client, song);
return;
}
if (!tag)
return;
for (unsigned i = 0; i < tag->num_items; i++) {
if (tag->items[i]->type == tagType) {
strset_add(set, tag->items[i]->value);
found = true;
}
}
if (!found)
strset_add(set, "");
}
struct list_tags_data {
struct client *client;
ListCommandItem *item;
struct strset *set;
static const struct db_visitor add_to_spl_visitor = {
.song = add_to_spl_song,
};
static int
listUniqueTagsInDirectory(struct song *song, void *_data)
bool
addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8,
GError **error_r)
{
struct list_tags_data *data = _data;
ListCommandItem *item = data->item;
if (locate_song_match(song, item->criteria))
visitTag(data->client, data->set, song, item->tagType);
return 0;
}
int listAllUniqueTags(struct client *client, int type,
const struct locate_item_list *criteria)
{
int ret;
ListCommandItem *item = newListCommandItem(type, criteria);
struct list_tags_data data = {
.client = client,
.item = item,
struct add_data data = {
.path = path_utf8,
};
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
data.set = strset_new();
}
ret = db_walk(NULL, listUniqueTagsInDirectory, NULL, &data);
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
const char *value;
strset_rewind(data.set);
while ((value = strset_next(data.set)) != NULL)
client_printf(client, "%s: %s\n",
tag_item_names[type],
value);
strset_free(data.set);
}
freeListCommandItem(item);
return ret;
return db_walk(uri_utf8, &add_to_spl_visitor, &data, error_r);
}
struct find_add_data {
struct player_control *pc;
const struct locate_item_list *criteria;
};
static bool
find_add_song(struct song *song, void *ctx, GError **error_r)
{
struct find_add_data *data = ctx;
if (!locate_song_match(song, data->criteria))
return true;
enum playlist_result result =
playlist_append_song(&g_playlist, data->pc,
song, NULL);
if (result != PLAYLIST_RESULT_SUCCESS) {
g_set_error(error_r, playlist_quark(), result,
"Playlist error");
return false;
}
return true;
}
static const struct db_visitor find_add_visitor = {
.song = find_add_song,
};
bool
findAddIn(struct player_control *pc, const char *name,
const struct locate_item_list *criteria, GError **error_r)
{
struct find_add_data data;
data.pc = pc;
data.criteria = criteria;
return db_walk(name, &find_add_visitor, &data, error_r);
}
static bool
searchadd_visitor_song(struct song *song, void *_data, GError **error_r)
{
struct find_add_data *data = _data;
if (!locate_song_search(song, data->criteria))
return true;
enum playlist_result result =
playlist_append_song(&g_playlist, data->pc, song, NULL);
if (result != PLAYLIST_RESULT_SUCCESS) {
g_set_error(error_r, playlist_quark(), result,
"Playlist error");
return false;
}
return true;
}
static const struct db_visitor searchadd_visitor = {
.song = searchadd_visitor_song,
};
bool
search_add_songs(struct player_control *pc, const char *uri,
const struct locate_item_list *criteria,
GError **error_r)
{
struct locate_item_list *new_list =
locate_item_list_casefold(criteria);
struct find_add_data data = {
.pc = pc,
.criteria = new_list,
};
bool success = db_walk(uri, &searchadd_visitor, &data, error_r);
locate_item_list_free(new_list);
return success;
}
struct search_add_playlist_data {
const char *playlist;
const struct locate_item_list *criteria;
};
static bool
searchaddpl_visitor_song(struct song *song, void *_data,
G_GNUC_UNUSED GError **error_r)
{
struct search_add_playlist_data *data = _data;
if (!locate_song_search(song, data->criteria))
return true;
if (!spl_append_song(data->playlist, song, error_r))
return false;
return true;
}
static const struct db_visitor searchaddpl_visitor = {
.song = searchaddpl_visitor_song,
};
bool
search_add_to_playlist(const char *uri, const char *path_utf8,
const struct locate_item_list *criteria,
GError **error_r)
{
struct locate_item_list *new_list
= locate_item_list_casefold(criteria);
struct search_add_playlist_data data = {
.playlist = path_utf8,
.criteria = new_list,
};
bool success = db_walk(uri, &searchaddpl_visitor, &data, error_r);
locate_item_list_free(new_list);
return success;
}

@@ -1,5 +1,5 @@
/*
* Copyright (C) 2003-2010 The Music Player Daemon Project
* Copyright (C) 2003-2011 The Music Player Daemon Project
* http://www.musicpd.org
*
* This program is free software; you can redistribute it and/or modify
@@ -20,37 +20,37 @@
#ifndef MPD_DB_UTILS_H
#define MPD_DB_UTILS_H
struct client;
#include "gcc.h"
#include <glib.h>
#include <stdbool.h>
struct locate_item_list;
struct player_control;
int printAllIn(struct client *client, const char *name);
gcc_nonnull(1,2)
bool
addAllIn(struct player_control *pc, const char *uri, GError **error_r);
int addAllIn(const char *name);
gcc_nonnull(1,2)
bool
addAllInToStoredPlaylist(const char *uri_utf8, const char *path_utf8,
GError **error_r);
int addAllInToStoredPlaylist(const char *name, const char *utf8file);
gcc_nonnull(1,2,3)
bool
findAddIn(struct player_control *pc, const char *name,
const struct locate_item_list *criteria, GError **error_r);
int printInfoForAllIn(struct client *client, const char *name);
gcc_nonnull(1,2,3)
bool
search_add_songs(struct player_control *pc, const char *uri,
const struct locate_item_list *criteria, GError **error_r);
int
searchForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria);
int
findSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria);
int
findAddIn(struct client *client, const char *name,
const struct locate_item_list *criteria);
int
searchStatsForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria);
unsigned long sumSongTimesIn(const char *name);
int
listAllUniqueTags(struct client *client, int type,
const struct locate_item_list *criteria);
gcc_nonnull(1,2,3)
bool
search_add_to_playlist(const char *uri, const char *path_utf8,
const struct locate_item_list *criteria,
GError **error_r);
#endif

45
src/db_error.h Normal file

@@ -0,0 +1,45 @@
/*
* Copyright (C) 2003-2011 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_DB_ERROR_H
#define MPD_DB_ERROR_H
#include <glib.h>
enum db_error {
/**
* The database is disabled, i.e. none is configured in this
* MPD instance.
*/
DB_DISABLED,
DB_NOT_FOUND,
};
/**
* Quark for GError.domain; the code is an enum #db_error.
*/
G_GNUC_CONST
static inline GQuark
db_quark(void)
{
return g_quark_from_static_string("db");
}
#endif

35
src/db_internal.h Normal file

@@ -0,0 +1,35 @@
/*
* Copyright (C) 2003-2011 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_DB_INTERNAL_H
#define MPD_DB_INTERNAL_H
#include "db_plugin.h"
#include <assert.h>
static inline void
db_base_init(struct db *db, const struct db_plugin *plugin)
{
assert(plugin != NULL);
db->plugin = plugin;
}
#endif

33
src/db_lock.c Normal file

@@ -0,0 +1,33 @@
/*
* Copyright (C) 2003-2011 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 "db_lock.h"
#include "gcc.h"
#if GCC_CHECK_VERSION(4, 2)
/* workaround for a warning caused by G_STATIC_MUTEX_INIT */
#pragma GCC diagnostic ignored "-Wmissing-field-initializers"
#endif
GStaticMutex db_mutex = G_STATIC_MUTEX_INIT;
#ifndef NDEBUG
GThread *db_mutex_holder;
#endif

84
src/db_lock.h Normal file

@@ -0,0 +1,84 @@
/*
* Copyright (C) 2003-2011 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.
*/
/** \file
*
* Support for locking data structures from the database, for safe
* multi-threading.
*/
#ifndef MPD_DB_LOCK_H
#define MPD_DB_LOCK_H
#include "check.h"
#include <glib.h>
#include <assert.h>
#include <stdbool.h>
extern GStaticMutex db_mutex;
#ifndef NDEBUG
extern GThread *db_mutex_holder;
/**
* Does the current thread hold the database lock?
*/
G_GNUC_PURE
static inline bool
holding_db_lock(void)
{
return db_mutex_holder == g_thread_self();
}
#endif
/**
* Obtain the global database lock. This is needed before
* dereferencing a #song or #directory. It is not recursive.
*/
static inline void
db_lock(void)
{
assert(!holding_db_lock());
g_static_mutex_lock(&db_mutex);
assert(db_mutex_holder == NULL);
#ifndef NDEBUG
db_mutex_holder = g_thread_self();
#endif
}
/**
* Release the global database lock.
*/
static inline void
db_unlock(void)
{
assert(holding_db_lock());
#ifndef NDEBUG
db_mutex_holder = NULL;
#endif
g_static_mutex_unlock(&db_mutex);
}
#endif

156
src/db_plugin.h Normal file

@@ -0,0 +1,156 @@
/*
* Copyright (C) 2003-2011 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.
*/
/** \file
*
* This header declares the db_plugin class. It describes a
* plugin API for databases of song metadata.
*/
#ifndef MPD_DB_PLUGIN_H
#define MPD_DB_PLUGIN_H
#include <glib.h>
#include <assert.h>
#include <stdbool.h>
struct config_param;
struct db_selection;
struct db_visitor;
struct db {
const struct db_plugin *plugin;
};
struct db_plugin {
const char *name;
/**
* Allocates and configures a database.
*/
struct db *(*init)(const struct config_param *param, GError **error_r);
/**
* Free instance data.
*/
void (*finish)(struct db *db);
/**
* Open the database. Read it into memory if applicable.
*/
bool (*open)(struct db *db, GError **error_r);
/**
* Close the database, free allocated memory.
*/
void (*close)(struct db *db);
/**
* Look up a song (including tag data) in the database.
*
* @param the URI of the song within the music directory
* (UTF-8)
*/
struct song *(*get_song)(struct db *db, const char *uri,
GError **error_r);
/**
* Visit the selected entities.
*/
bool (*visit)(struct db *db, const struct db_selection *selection,
const struct db_visitor *visitor, void *ctx,
GError **error_r);
};
G_GNUC_MALLOC
static inline struct db *
db_plugin_new(const struct db_plugin *plugin, const struct config_param *param,
GError **error_r)
{
assert(plugin != NULL);
assert(plugin->init != NULL);
assert(plugin->finish != NULL);
assert(plugin->get_song != NULL);
assert(plugin->visit != NULL);
assert(error_r == NULL || *error_r == NULL);
struct db *db = plugin->init(param, error_r);
assert(db == NULL || db->plugin == plugin);
assert(db != NULL || error_r == NULL || *error_r != NULL);
return db;
}
static inline void
db_plugin_free(struct db *db)
{
assert(db != NULL);
assert(db->plugin != NULL);
assert(db->plugin->finish != NULL);
db->plugin->finish(db);
}
static inline bool
db_plugin_open(struct db *db, GError **error_r)
{
assert(db != NULL);
assert(db->plugin != NULL);
return db->plugin->open != NULL
? db->plugin->open(db, error_r)
: true;
}
static inline void
db_plugin_close(struct db *db)
{
assert(db != NULL);
assert(db->plugin != NULL);
if (db->plugin->close != NULL)
db->plugin->close(db);
}
static inline struct song *
db_plugin_get_song(struct db *db, const char *uri, GError **error_r)
{
assert(db != NULL);
assert(db->plugin != NULL);
assert(db->plugin->get_song != NULL);
assert(uri != NULL);
return db->plugin->get_song(db, uri, error_r);
}
static inline bool
db_plugin_visit(struct db *db, const struct db_selection *selection,
const struct db_visitor *visitor, void *ctx,
GError **error_r)
{
assert(db != NULL);
assert(db->plugin != NULL);
assert(selection != NULL);
assert(visitor != NULL);
assert(error_r == NULL || *error_r == NULL);
return db->plugin->visit(db, selection, visitor, ctx, error_r);
}
#endif

393
src/db_print.c Normal file

@@ -0,0 +1,393 @@
/*
* Copyright (C) 2003-2011 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 "db_print.h"
#include "db_selection.h"
#include "db_visitor.h"
#include "locate.h"
#include "directory.h"
#include "database.h"
#include "client.h"
#include "song.h"
#include "song_print.h"
#include "playlist_vector.h"
#include "tag.h"
#include "strset.h"
#include <glib.h>
typedef struct _ListCommandItem {
int8_t tagType;
const struct locate_item_list *criteria;
} ListCommandItem;
typedef struct _SearchStats {
const struct locate_item_list *criteria;
int numberOfSongs;
unsigned long playTime;
} SearchStats;
static bool
print_visitor_directory(const struct directory *directory, void *data,
G_GNUC_UNUSED GError **error_r)
{
struct client *client = data;
if (!directory_is_root(directory))
client_printf(client, "directory: %s\n", directory_get_path(directory));
return true;
}
static void
print_playlist_in_directory(struct client *client,
const struct directory *directory,
const char *name_utf8)
{
if (directory_is_root(directory))
client_printf(client, "playlist: %s\n", name_utf8);
else
client_printf(client, "playlist: %s/%s\n",
directory_get_path(directory), name_utf8);
}
static bool
print_visitor_song(struct song *song, void *data,
G_GNUC_UNUSED GError **error_r)
{
assert(song != NULL);
assert(song->parent != NULL);
struct client *client = data;
song_print_uri(client, song);
if (song->tag != NULL && song->tag->has_playlist)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory(client, song->parent,
song->uri);
return true;
}
static bool
print_visitor_song_info(struct song *song, void *data,
G_GNUC_UNUSED GError **error_r)
{
assert(song != NULL);
assert(song->parent != NULL);
struct client *client = data;
song_print_info(client, song);
if (song->tag != NULL && song->tag->has_playlist)
/* this song file has an embedded CUE sheet */
print_playlist_in_directory(client, song->parent,
song->uri);
return true;
}
static bool
print_visitor_playlist(const struct playlist_metadata *playlist,
const struct directory *directory, void *ctx,
G_GNUC_UNUSED GError **error_r)
{
struct client *client = ctx;
print_playlist_in_directory(client, directory, playlist->name);
return true;
}
static bool
print_visitor_playlist_info(const struct playlist_metadata *playlist,
const struct directory *directory,
void *ctx, G_GNUC_UNUSED GError **error_r)
{
struct client *client = ctx;
print_playlist_in_directory(client, directory, playlist->name);
#ifndef G_OS_WIN32
struct tm tm;
#endif
char timestamp[32];
time_t t = playlist->mtime;
strftime(timestamp, sizeof(timestamp),
#ifdef G_OS_WIN32
"%Y-%m-%dT%H:%M:%SZ",
gmtime(&t)
#else
"%FT%TZ",
gmtime_r(&t, &tm)
#endif
);
client_printf(client, "Last-Modified: %s\n", timestamp);
return true;
}
static const struct db_visitor print_visitor = {
.directory = print_visitor_directory,
.song = print_visitor_song,
.playlist = print_visitor_playlist,
};
static const struct db_visitor print_info_visitor = {
.directory = print_visitor_directory,
.song = print_visitor_song_info,
.playlist = print_visitor_playlist_info,
};
bool
db_selection_print(struct client *client, const struct db_selection *selection,
bool full, GError **error_r)
{
return db_visit(selection, full ? &print_info_visitor : &print_visitor,
client, error_r);
}
struct search_data {
struct client *client;
const struct locate_item_list *criteria;
};
static bool
search_visitor_song(struct song *song, void *_data,
G_GNUC_UNUSED GError **error_r)
{
struct search_data *data = _data;
if (locate_song_search(song, data->criteria))
song_print_info(data->client, song);
return true;
}
static const struct db_visitor search_visitor = {
.song = search_visitor_song,
};
bool
searchForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria,
GError **error_r)
{
struct locate_item_list *new_list
= locate_item_list_casefold(criteria);
struct search_data data;
data.client = client;
data.criteria = new_list;
bool success = db_walk(name, &search_visitor, &data, error_r);
locate_item_list_free(new_list);
return success;
}
static bool
find_visitor_song(struct song *song, void *_data,
G_GNUC_UNUSED GError **error_r)
{
struct search_data *data = _data;
if (locate_song_match(song, data->criteria))
song_print_info(data->client, song);
return true;
}
static const struct db_visitor find_visitor = {
.song = find_visitor_song,
};
bool
findSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria,
GError **error_r)
{
struct search_data data;
data.client = client;
data.criteria = criteria;
return db_walk(name, &find_visitor, &data, error_r);
}
static void printSearchStats(struct client *client, SearchStats *stats)
{
client_printf(client, "songs: %i\n", stats->numberOfSongs);
client_printf(client, "playtime: %li\n", stats->playTime);
}
static bool
stats_visitor_song(struct song *song, void *data,
G_GNUC_UNUSED GError **error_r)
{
SearchStats *stats = data;
if (locate_song_match(song, stats->criteria)) {
stats->numberOfSongs++;
stats->playTime += song_get_duration(song);
}
return true;
}
static const struct db_visitor stats_visitor = {
.song = stats_visitor_song,
};
bool
searchStatsForSongsIn(struct client *client, const char *name,
const struct locate_item_list *criteria,
GError **error_r)
{
SearchStats stats;
stats.criteria = criteria;
stats.numberOfSongs = 0;
stats.playTime = 0;
if (!db_walk(name, &stats_visitor, &stats, error_r))
return false;
printSearchStats(client, &stats);
return true;
}
bool
printAllIn(struct client *client, const char *uri_utf8, GError **error_r)
{
struct db_selection selection;
db_selection_init(&selection, uri_utf8, true);
return db_selection_print(client, &selection, false, error_r);
}
bool
printInfoForAllIn(struct client *client, const char *uri_utf8,
GError **error_r)
{
struct db_selection selection;
db_selection_init(&selection, uri_utf8, true);
return db_selection_print(client, &selection, true, error_r);
}
static ListCommandItem *
newListCommandItem(int tagType, const struct locate_item_list *criteria)
{
ListCommandItem *item = g_new(ListCommandItem, 1);
item->tagType = tagType;
item->criteria = criteria;
return item;
}
static void freeListCommandItem(ListCommandItem * item)
{
g_free(item);
}
static void
visitTag(struct client *client, struct strset *set,
struct song *song, enum tag_type tagType)
{
struct tag *tag = song->tag;
bool found = false;
if (tagType == LOCATE_TAG_FILE_TYPE) {
song_print_uri(client, song);
return;
}
if (!tag)
return;
for (unsigned i = 0; i < tag->num_items; i++) {
if (tag->items[i]->type == tagType) {
strset_add(set, tag->items[i]->value);
found = true;
}
}
if (!found)
strset_add(set, "");
}
struct list_tags_data {
struct client *client;
ListCommandItem *item;
struct strset *set;
};
static bool
unique_tags_visitor_song(struct song *song, void *_data,
G_GNUC_UNUSED GError **error_r)
{
struct list_tags_data *data = _data;
ListCommandItem *item = data->item;
if (locate_song_match(song, item->criteria))
visitTag(data->client, data->set, song, item->tagType);
return true;
}
static const struct db_visitor unique_tags_visitor = {
.song = unique_tags_visitor_song,
};
bool
listAllUniqueTags(struct client *client, int type,
const struct locate_item_list *criteria,
GError **error_r)
{
ListCommandItem *item = newListCommandItem(type, criteria);
struct list_tags_data data = {
.client = client,
.item = item,
};
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
data.set = strset_new();
}
if (!db_walk("", &unique_tags_visitor, &data, error_r)) {
freeListCommandItem(item);
return false;
}
if (type >= 0 && type <= TAG_NUM_OF_ITEM_TYPES) {
const char *value;
strset_rewind(data.set);
while ((value = strset_next(data.set)) != NULL)
client_printf(client, "%s: %s\n",
tag_item_names[type],
value);
strset_free(data.set);
}
freeListCommandItem(item);
return true;
}

Some files were not shown because too many files have changed in this diff Show More