diff --git a/NEWS b/NEWS index 4f9c7da02..fb513cd79 100644 --- a/NEWS +++ b/NEWS @@ -68,10 +68,16 @@ ver 0.19 (not yet released) * install systemd unit for socket activation * Android port -ver 0.18.13 (not yet released) +ver 0.18.13 (2014/08/31) +* protocol + - don't change song on "seekcur" in random mode + * decoder - dsdiff, dsf: fix endless loop on malformed file - ffmpeg: support ffmpeg/libav version 11 + - gme: fix song duration +* output + - alsa: fix endless loop at end of file in dsd_usb mode * fix state file saver * fix build failure on Darwin diff --git a/doc/protocol.xml b/doc/protocol.xml index af2a312d2..8e114dfbd 100644 --- a/doc/protocol.xml +++ b/doc/protocol.xml @@ -576,7 +576,12 @@ - songs: number of albums + albums: number of albums + + + + + songs: number of songs diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx index a18cedc70..0ebf3ddbe 100644 --- a/src/output/plugins/AlsaOutputPlugin.cxx +++ b/src/output/plugins/AlsaOutputPlugin.cxx @@ -825,6 +825,7 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size, { AlsaOutput *ad = (AlsaOutput *)ao; + assert(size > 0); assert(size % ad->in_frame_size == 0); if (ad->must_prepare) { @@ -838,12 +839,22 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size, } const auto e = ad->pcm_export->Export({chunk, size}); + if (e.size == 0) + /* the DoP (DSD over PCM) filter converts two frames + at a time and ignores the last odd frame; if there + was only one frame (e.g. the last frame in the + file), the result is empty; to avoid an endless + loop, bail out here, and pretend the one frame has + been played */ + return size; + chunk = e.data; size = e.size; assert(size % ad->out_frame_size == 0); size /= ad->out_frame_size; + assert(size > 0); while (true) { snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size); diff --git a/src/output/plugins/OssOutputPlugin.cxx b/src/output/plugins/OssOutputPlugin.cxx index f2618491c..39d87fc35 100644 --- a/src/output/plugins/OssOutputPlugin.cxx +++ b/src/output/plugins/OssOutputPlugin.cxx @@ -724,6 +724,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size, OssOutput *od = (OssOutput *)ao; ssize_t ret; + assert(size > 0); + /* reopen the device since it was closed by dropBufferedAudio */ if (od->fd < 0 && !oss_reopen(od, error)) return 0; @@ -734,6 +736,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size, size = e.size; #endif + assert(size > 0); + while (true) { ret = write(od->fd, chunk, size); if (ret > 0) { diff --git a/src/queue/Playlist.hxx b/src/queue/Playlist.hxx index 581d2a73b..ea19d9bba 100644 --- a/src/queue/Playlist.hxx +++ b/src/queue/Playlist.hxx @@ -251,6 +251,10 @@ public: void PlayPrevious(PlayerControl &pc); + PlaylistResult SeekSongOrder(PlayerControl &pc, + unsigned song_order, + SongTime seek_time); + PlaylistResult SeekSongPosition(PlayerControl &pc, unsigned song_position, SongTime seek_time); diff --git a/src/queue/PlaylistControl.cxx b/src/queue/PlaylistControl.cxx index df6b6ed0f..f7e80dc46 100644 --- a/src/queue/PlaylistControl.cxx +++ b/src/queue/PlaylistControl.cxx @@ -190,18 +190,12 @@ playlist::PlayPrevious(PlayerControl &pc) } PlaylistResult -playlist::SeekSongPosition(PlayerControl &pc, - unsigned song, SongTime seek_time) +playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time) { - if (!queue.IsValidPosition(song)) - return PlaylistResult::BAD_RANGE; + assert(queue.IsValidOrder(i)); const DetachedSong *queued_song = GetQueuedSong(); - unsigned i = queue.random - ? queue.PositionToOrder(song) - : song; - pc.ClearError(); stop_on_error = true; error_count = 0; @@ -228,6 +222,20 @@ playlist::SeekSongPosition(PlayerControl &pc, return PlaylistResult::SUCCESS; } +PlaylistResult +playlist::SeekSongPosition(PlayerControl &pc, unsigned song, + SongTime seek_time) +{ + if (!queue.IsValidPosition(song)) + return PlaylistResult::BAD_RANGE; + + unsigned i = queue.random + ? queue.PositionToOrder(song) + : song; + + return SeekSongOrder(pc, i, seek_time); +} + PlaylistResult playlist::SeekSongId(PlayerControl &pc, unsigned id, SongTime seek_time) { @@ -257,5 +265,8 @@ playlist::SeekCurrent(PlayerControl &pc, seek_time = SignedSongTime::zero(); } - return SeekSongPosition(pc, current, SongTime(seek_time)); + if (seek_time.IsNegative()) + seek_time = SignedSongTime::zero(); + + return SeekSongOrder(pc, current, SongTime(seek_time)); }