Commit 6e04d66a authored by Max Kellermann's avatar Max Kellermann

Merge tag 'v0.18.13'

parents 26bef5d2 86e8b3b4
...@@ -68,10 +68,16 @@ ver 0.19 (not yet released) ...@@ -68,10 +68,16 @@ ver 0.19 (not yet released)
* install systemd unit for socket activation * install systemd unit for socket activation
* Android port * 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 * decoder
- dsdiff, dsf: fix endless loop on malformed file - dsdiff, dsf: fix endless loop on malformed file
- ffmpeg: support ffmpeg/libav version 11 - 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 state file saver
* fix build failure on Darwin * fix build failure on Darwin
......
...@@ -576,7 +576,12 @@ ...@@ -576,7 +576,12 @@
</listitem> </listitem>
<listitem> <listitem>
<para> <para>
<varname>songs</varname>: number of albums <varname>albums</varname>: number of albums
</para>
</listitem>
<listitem>
<para>
<varname>songs</varname>: number of songs
</para> </para>
</listitem> </listitem>
<listitem> <listitem>
......
...@@ -825,6 +825,7 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size, ...@@ -825,6 +825,7 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size,
{ {
AlsaOutput *ad = (AlsaOutput *)ao; AlsaOutput *ad = (AlsaOutput *)ao;
assert(size > 0);
assert(size % ad->in_frame_size == 0); assert(size % ad->in_frame_size == 0);
if (ad->must_prepare) { if (ad->must_prepare) {
...@@ -838,12 +839,22 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size, ...@@ -838,12 +839,22 @@ alsa_play(AudioOutput *ao, const void *chunk, size_t size,
} }
const auto e = ad->pcm_export->Export({chunk, 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; chunk = e.data;
size = e.size; size = e.size;
assert(size % ad->out_frame_size == 0); assert(size % ad->out_frame_size == 0);
size /= ad->out_frame_size; size /= ad->out_frame_size;
assert(size > 0);
while (true) { while (true) {
snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size); snd_pcm_sframes_t ret = ad->writei(ad->pcm, chunk, size);
......
...@@ -724,6 +724,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size, ...@@ -724,6 +724,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size,
OssOutput *od = (OssOutput *)ao; OssOutput *od = (OssOutput *)ao;
ssize_t ret; ssize_t ret;
assert(size > 0);
/* reopen the device since it was closed by dropBufferedAudio */ /* reopen the device since it was closed by dropBufferedAudio */
if (od->fd < 0 && !oss_reopen(od, error)) if (od->fd < 0 && !oss_reopen(od, error))
return 0; return 0;
...@@ -734,6 +736,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size, ...@@ -734,6 +736,8 @@ oss_output_play(AudioOutput *ao, const void *chunk, size_t size,
size = e.size; size = e.size;
#endif #endif
assert(size > 0);
while (true) { while (true) {
ret = write(od->fd, chunk, size); ret = write(od->fd, chunk, size);
if (ret > 0) { if (ret > 0) {
......
...@@ -251,6 +251,10 @@ public: ...@@ -251,6 +251,10 @@ public:
void PlayPrevious(PlayerControl &pc); void PlayPrevious(PlayerControl &pc);
PlaylistResult SeekSongOrder(PlayerControl &pc,
unsigned song_order,
SongTime seek_time);
PlaylistResult SeekSongPosition(PlayerControl &pc, PlaylistResult SeekSongPosition(PlayerControl &pc,
unsigned song_position, unsigned song_position,
SongTime seek_time); SongTime seek_time);
......
...@@ -190,18 +190,12 @@ playlist::PlayPrevious(PlayerControl &pc) ...@@ -190,18 +190,12 @@ playlist::PlayPrevious(PlayerControl &pc)
} }
PlaylistResult PlaylistResult
playlist::SeekSongPosition(PlayerControl &pc, playlist::SeekSongOrder(PlayerControl &pc, unsigned i, SongTime seek_time)
unsigned song, SongTime seek_time)
{ {
if (!queue.IsValidPosition(song)) assert(queue.IsValidOrder(i));
return PlaylistResult::BAD_RANGE;
const DetachedSong *queued_song = GetQueuedSong(); const DetachedSong *queued_song = GetQueuedSong();
unsigned i = queue.random
? queue.PositionToOrder(song)
: song;
pc.ClearError(); pc.ClearError();
stop_on_error = true; stop_on_error = true;
error_count = 0; error_count = 0;
...@@ -229,6 +223,20 @@ playlist::SeekSongPosition(PlayerControl &pc, ...@@ -229,6 +223,20 @@ playlist::SeekSongPosition(PlayerControl &pc,
} }
PlaylistResult 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) playlist::SeekSongId(PlayerControl &pc, unsigned id, SongTime seek_time)
{ {
int song = queue.IdToPosition(id); int song = queue.IdToPosition(id);
...@@ -257,5 +265,8 @@ playlist::SeekCurrent(PlayerControl &pc, ...@@ -257,5 +265,8 @@ playlist::SeekCurrent(PlayerControl &pc,
seek_time = SignedSongTime::zero(); 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));
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment