diff options
author | Max Kellermann <max@duempel.org> | 2014-07-11 21:33:50 +0200 |
---|---|---|
committer | Max Kellermann <max@duempel.org> | 2014-07-11 21:33:50 +0200 |
commit | 828cd6fd0b8838edb39e6b3f62397a5fe369e1d5 (patch) | |
tree | 62bfa8fdaaf846a5a4c18e6607ef8f1e8f13c8a2 /src | |
parent | 681643ea9e6e196c449f1974cd50e1f400da3450 (diff) | |
parent | ecb67a1ed16e93f5fe552b28631e517060115648 (diff) | |
download | mpd-828cd6fd0b8838edb39e6b3f62397a5fe369e1d5.tar.gz mpd-828cd6fd0b8838edb39e6b3f62397a5fe369e1d5.tar.xz mpd-828cd6fd0b8838edb39e6b3f62397a5fe369e1d5.zip |
Merge branch 'v0.18.x'
Diffstat (limited to 'src')
-rw-r--r-- | src/BulkEdit.hxx | 41 | ||||
-rw-r--r-- | src/command/DatabaseCommands.cxx | 3 | ||||
-rw-r--r-- | src/command/PlaylistCommands.cxx | 3 | ||||
-rw-r--r-- | src/command/QueueCommands.cxx | 3 | ||||
-rw-r--r-- | src/decoder/plugins/AudiofileDecoderPlugin.cxx | 6 | ||||
-rw-r--r-- | src/decoder/plugins/SndfileDecoderPlugin.cxx | 55 | ||||
-rw-r--r-- | src/queue/Playlist.cxx | 10 | ||||
-rw-r--r-- | src/queue/Playlist.hxx | 19 | ||||
-rw-r--r-- | src/queue/PlaylistControl.cxx | 2 | ||||
-rw-r--r-- | src/queue/PlaylistEdit.cxx | 35 |
10 files changed, 144 insertions, 33 deletions
diff --git a/src/BulkEdit.hxx b/src/BulkEdit.hxx new file mode 100644 index 000000000..422dc4f38 --- /dev/null +++ b/src/BulkEdit.hxx @@ -0,0 +1,41 @@ +/* + * Copyright (C) 2003-2014 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_BULK_EDIT_HXX +#define MPD_BULK_EDIT_HXX + +#include "Partition.hxx" + +/** + * Begin a "bulk edit" and commit it automatically. + */ +class ScopeBulkEdit { + Partition &partition; + +public: + ScopeBulkEdit(Partition &_partition):partition(_partition) { + partition.playlist.BeginBulk(); + } + + ~ScopeBulkEdit() { + partition.playlist.CommitBulk(partition.pc); + } +}; + +#endif diff --git a/src/command/DatabaseCommands.cxx b/src/command/DatabaseCommands.cxx index 70d97a63e..a3ea8d0ae 100644 --- a/src/command/DatabaseCommands.cxx +++ b/src/command/DatabaseCommands.cxx @@ -32,6 +32,7 @@ #include "util/Error.hxx" #include "SongFilter.hxx" #include "protocol/Result.hxx" +#include "BulkEdit.hxx" #include <string.h> @@ -106,6 +107,8 @@ handle_match_add(Client &client, unsigned argc, char *argv[], bool fold_case) return CommandResult::ERROR; } + const ScopeBulkEdit bulk_edit(client.partition); + const DatabaseSelection selection("", true, &filter); Error error; return AddFromDatabase(client.partition, selection, error) diff --git a/src/command/PlaylistCommands.cxx b/src/command/PlaylistCommands.cxx index 79bfb44d8..c2b18064c 100644 --- a/src/command/PlaylistCommands.cxx +++ b/src/command/PlaylistCommands.cxx @@ -26,6 +26,7 @@ #include "PlaylistFile.hxx" #include "db/PlaylistVector.hxx" #include "SongLoader.hxx" +#include "BulkEdit.hxx" #include "playlist/PlaylistQueue.hxx" #include "playlist/Print.hxx" #include "queue/Playlist.hxx" @@ -66,6 +67,8 @@ handle_load(Client &client, unsigned argc, char *argv[]) } else if (!check_range(client, &start_index, &end_index, argv[2])) return CommandResult::ERROR; + const ScopeBulkEdit bulk_edit(client.partition); + Error error; const SongLoader loader(client); if (!playlist_open_into_queue(argv[1], diff --git a/src/command/QueueCommands.cxx b/src/command/QueueCommands.cxx index 0d0cff5cf..1ff7a732b 100644 --- a/src/command/QueueCommands.cxx +++ b/src/command/QueueCommands.cxx @@ -28,6 +28,7 @@ #include "PlaylistPrint.hxx" #include "client/Client.hxx" #include "Partition.hxx" +#include "BulkEdit.hxx" #include "protocol/ArgParser.hxx" #include "protocol/Result.hxx" #include "ls.hxx" @@ -74,6 +75,8 @@ handle_add(Client &client, gcc_unused unsigned argc, char *argv[]) } #ifdef ENABLE_DATABASE + const ScopeBulkEdit bulk_edit(client.partition); + const DatabaseSelection selection(uri, true); Error error; return AddFromDatabase(client.partition, selection, error) diff --git a/src/decoder/plugins/AudiofileDecoderPlugin.cxx b/src/decoder/plugins/AudiofileDecoderPlugin.cxx index 603f714d1..93a6e03a2 100644 --- a/src/decoder/plugins/AudiofileDecoderPlugin.cxx +++ b/src/decoder/plugins/AudiofileDecoderPlugin.cxx @@ -55,7 +55,7 @@ struct AudioFileInputStream { size_t Read(void *buffer, size_t size) { /* libaudiofile does not like partial reads at all, - and wil abort playback; therefore always force full + and will abort playback; therefore always force full reads */ return decoder_read_full(decoder, is, buffer, size) ? size @@ -118,9 +118,11 @@ audiofile_file_seek(AFvirtualfile *vfile, AFfileoffset _offset, if (is_relative) offset += is.GetOffset(); - if (is.LockSeek(offset, IgnoreError())) { + Error error; + if (is.LockSeek(offset, error)) { return is.GetOffset(); } else { + LogError(error, "Seek failed"); return -1; } } diff --git a/src/decoder/plugins/SndfileDecoderPlugin.cxx b/src/decoder/plugins/SndfileDecoderPlugin.cxx index cf3aa61d5..1901ea7e4 100644 --- a/src/decoder/plugins/SndfileDecoderPlugin.cxx +++ b/src/decoder/plugins/SndfileDecoderPlugin.cxx @@ -32,10 +32,24 @@ static constexpr Domain sndfile_domain("sndfile"); +struct SndfileInputStream { + Decoder *const decoder; + InputStream &is; + + size_t Read(void *buffer, size_t size) { + /* libsndfile chokes on partial reads; therefore + always force full reads */ + return decoder_read_full(decoder, is, buffer, size) + ? size + : 0; + } +}; + static sf_count_t sndfile_vio_get_filelen(void *user_data) { - const InputStream &is = *(const InputStream *)user_data; + SndfileInputStream &sis = *(SndfileInputStream *)user_data; + const InputStream &is = sis.is; return is.GetSize(); } @@ -43,7 +57,8 @@ sndfile_vio_get_filelen(void *user_data) static sf_count_t sndfile_vio_seek(sf_count_t _offset, int whence, void *user_data) { - InputStream &is = *(InputStream *)user_data; + SndfileInputStream &sis = *(SndfileInputStream *)user_data; + InputStream &is = sis.is; InputStream::offset_type offset = _offset; switch (whence) { @@ -65,8 +80,11 @@ sndfile_vio_seek(sf_count_t _offset, int whence, void *user_data) return -1; } - if (!is.LockSeek(offset, IgnoreError())) + Error error; + if (!is.LockSeek(offset, error)) { + LogError(error, "Seek failed"); return -1; + } return is.GetOffset(); } @@ -74,30 +92,9 @@ sndfile_vio_seek(sf_count_t _offset, int whence, void *user_data) static sf_count_t sndfile_vio_read(void *ptr, sf_count_t count, void *user_data) { - InputStream &is = *(InputStream *)user_data; - - sf_count_t total_bytes = 0; - Error error; - - /* this loop is necessary because libsndfile chokes on partial - reads */ - - do { - size_t nbytes = is.LockRead((char *)ptr + total_bytes, - count - total_bytes, error); - if (nbytes == 0) { - if (error.IsDefined()) { - LogError(error); - return -1; - } - - break; - } - - total_bytes += nbytes; - } while (total_bytes < count); + SndfileInputStream &sis = *(SndfileInputStream *)user_data; - return total_bytes; + return sis.Read(ptr, count); } static sf_count_t @@ -112,7 +109,8 @@ sndfile_vio_write(gcc_unused const void *ptr, static sf_count_t sndfile_vio_tell(void *user_data) { - const InputStream &is = *(const InputStream *)user_data; + SndfileInputStream &sis = *(SndfileInputStream *)user_data; + const InputStream &is = sis.is; return is.GetOffset(); } @@ -158,7 +156,8 @@ sndfile_stream_decode(Decoder &decoder, InputStream &is) info.format = 0; - sf = sf_open_virtual(&vio, SFM_READ, &info, &is); + SndfileInputStream sis{&decoder, is}; + sf = sf_open_virtual(&vio, SFM_READ, &info, &sis); if (sf == nullptr) { LogWarning(sndfile_domain, "sf_open_virtual() failed"); return; diff --git a/src/queue/Playlist.cxx b/src/queue/Playlist.cxx index abcb2ceaa..b2fd673b4 100644 --- a/src/queue/Playlist.cxx +++ b/src/queue/Playlist.cxx @@ -99,6 +99,12 @@ playlist::UpdateQueuedSong(PlayerControl &pc, const DetachedSong *prev) if (!playing) return; + if (prev == nullptr && bulk_edit) + /* postponed until CommitBulk() to avoid always + queueing the first song that is being added (in + random mode) */ + return; + assert(!queue.IsEmpty()); assert((queued < 0) == (prev == nullptr)); @@ -286,7 +292,9 @@ playlist::SetRandom(PlayerControl &pc, bool status) if (queue.random) { /* shuffle the queue order, but preserve current */ - const int current_position = GetCurrentPosition(); + const int current_position = playing + ? GetCurrentPosition() + : -1; queue.ShuffleOrder(); diff --git a/src/queue/Playlist.hxx b/src/queue/Playlist.hxx index 4a4c7f30c..f2d778382 100644 --- a/src/queue/Playlist.hxx +++ b/src/queue/Playlist.hxx @@ -50,6 +50,18 @@ struct playlist { bool stop_on_error; /** + * If true, then a bulk edit has been initiated by + * BeginBulk(), and UpdateQueuedSong() and OnModified() will + * be postponed until CommitBulk() + */ + bool bulk_edit; + + /** + * Has the queue been modified during bulk edit mode? + */ + bool bulk_modified; + + /** * Number of errors since playback was started. If this * number exceeds the length of the playlist, MPD gives up, * because all songs have been tried. @@ -73,7 +85,9 @@ struct playlist { int queued; playlist(unsigned max_length) - :queue(max_length), playing(false), current(-1), queued(-1) { + :queue(max_length), playing(false), + bulk_edit(false), + current(-1), queued(-1) { } ~playlist() { @@ -130,6 +144,9 @@ protected: void UpdateQueuedSong(PlayerControl &pc, const DetachedSong *prev); public: + void BeginBulk(); + void CommitBulk(PlayerControl &pc); + void Clear(PlayerControl &pc); /** diff --git a/src/queue/PlaylistControl.cxx b/src/queue/PlaylistControl.cxx index 9d75cc26d..db0b8a25d 100644 --- a/src/queue/PlaylistControl.cxx +++ b/src/queue/PlaylistControl.cxx @@ -153,7 +153,7 @@ playlist::PlayNext(PlayerControl &pc) queue.ShuffleOrder(); /* note that current and queued are - now invalid, but playlist_play_order() will + now invalid, but PlayOrder() will discard them anyway */ } diff --git a/src/queue/PlaylistEdit.cxx b/src/queue/PlaylistEdit.cxx index e8f1a178f..92865cab7 100644 --- a/src/queue/PlaylistEdit.cxx +++ b/src/queue/PlaylistEdit.cxx @@ -38,6 +38,12 @@ void playlist::OnModified() { + if (bulk_edit) { + /* postponed to CommitBulk() */ + bulk_modified = true; + return; + } + queue.IncrementVersion(); idle_add(IDLE_PLAYLIST); @@ -54,6 +60,35 @@ playlist::Clear(PlayerControl &pc) OnModified(); } +void +playlist::BeginBulk() +{ + assert(!bulk_edit); + + bulk_edit = true; + bulk_modified = false; +} + +void +playlist::CommitBulk(PlayerControl &pc) +{ + assert(bulk_edit); + + bulk_edit = false; + if (!bulk_modified) + return; + + if (queued < 0) + /* if no song was queued, UpdateQueuedSong() is being + ignored in "bulk" edit mode; now that we have + shuffled all new songs, we can pick a random one + (instead of always picking the first one that was + added) */ + UpdateQueuedSong(pc, nullptr); + + OnModified(); +} + unsigned playlist::AppendSong(PlayerControl &pc, DetachedSong &&song, Error &error) { |