diff --git a/NEWS b/NEWS
index d9ba7a9f8..634c53f06 100644
--- a/NEWS
+++ b/NEWS
@@ -57,7 +57,11 @@ ver 0.20 (not yet released)
ver 0.19.20 (not yet released)
* decoder
- ffmpeg: ignore empty packets
+ - pcm: fix corruption bug with partial frames (after short read)
- sidplay: fix playback speed with libsidplayfp
+* output
+ - winmm: fix 8 bit playback
+* fix gcc 7.0 -Wimplicit-fallthrough
ver 0.19.19 (2016/08/23)
* decoder
diff --git a/doc/protocol.xml b/doc/protocol.xml
index 7959acd36..085d97c31 100644
--- a/doc/protocol.xml
+++ b/doc/protocol.xml
@@ -66,8 +66,8 @@
strcpy just fine with UTF-8 encoded
strings. For example: OK encoded in
UTF-8 is simply OK. For more
- information on UTF=8:
- http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)
+ information on UTF-8:
+ )
diff --git a/src/decoder/plugins/PcmDecoderPlugin.cxx b/src/decoder/plugins/PcmDecoderPlugin.cxx
index bc39b1324..ec1a643a0 100644
--- a/src/decoder/plugins/PcmDecoderPlugin.cxx
+++ b/src/decoder/plugins/PcmDecoderPlugin.cxx
@@ -25,16 +25,34 @@
#include "system/ByteOrder.hxx"
#include "util/Domain.hxx"
#include "util/ByteReverse.hxx"
+#include "util/StaticFifoBuffer.hxx"
#include "util/NumberParser.hxx"
#include "util/MimeType.hxx"
#include "Log.hxx"
#include
+#include
#include
static constexpr Domain pcm_decoder_domain("pcm_decoder");
+template
+static bool
+FillBuffer(Decoder &decoder, InputStream &is, B &buffer)
+{
+ buffer.Shift();
+ auto w = buffer.Write();
+ assert(!w.IsEmpty());
+
+ size_t nbytes = decoder_read(decoder, is, w.data, w.size);
+ if (nbytes == 0 && is.LockIsEOF())
+ return false;
+
+ buffer.Append(nbytes);
+ return true;
+}
+
static void
pcm_stream_decode(Decoder &decoder, InputStream &is)
{
@@ -128,25 +146,27 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
decoder_initialized(decoder, audio_format,
is.IsSeekable(), total_time);
+ StaticFifoBuffer buffer;
+
DecoderCommand cmd;
do {
- char buffer[4096];
-
- size_t nbytes = decoder_read(decoder, is,
- buffer, sizeof(buffer));
-
- if (nbytes == 0 && is.LockIsEOF())
+ if (!FillBuffer(decoder, is, buffer))
break;
+ auto r = buffer.Read();
+ /* round down to the nearest frame size, because we
+ must not pass partial frames to decoder_data() */
+ r.size -= r.size % frame_size;
+ buffer.Consume(r.size);
+
if (reverse_endian)
/* make sure we deliver samples in host byte order */
- reverse_bytes_16((uint16_t *)buffer,
- (uint16_t *)buffer,
- (uint16_t *)(buffer + nbytes));
+ reverse_bytes_16((uint16_t *)r.data,
+ (uint16_t *)r.data,
+ (uint16_t *)(r.data + r.size));
- cmd = nbytes > 0
- ? decoder_data(decoder, is,
- buffer, nbytes, 0)
+ cmd = !r.IsEmpty()
+ ? decoder_data(decoder, is, r.data, r.size, 0)
: decoder_get_command(decoder);
if (cmd == DecoderCommand::SEEK) {
uint64_t frame = decoder_seek_where_frame(decoder);
@@ -154,6 +174,7 @@ pcm_stream_decode(Decoder &decoder, InputStream &is)
try {
is.LockSeek(offset);
+ buffer.Clear();
decoder_command_finished(decoder);
} catch (const std::runtime_error &e) {
LogError(e);
diff --git a/src/input/plugins/AlsaInputPlugin.cxx b/src/input/plugins/AlsaInputPlugin.cxx
index 0c2d1da9f..8e337b1b7 100644
--- a/src/input/plugins/AlsaInputPlugin.cxx
+++ b/src/input/plugins/AlsaInputPlugin.cxx
@@ -223,6 +223,10 @@ AlsaInputStream::Recover(int err)
case -EPIPE:
LogDebug(alsa_input_domain, "Buffer Overrun");
// drop through
+#if GCC_CHECK_VERSION(7,0)
+ [[fallthrough]];
+#endif
+
case -ESTRPIPE:
case -EINTR:
err = snd_pcm_recover(capture_handle, err, 1);
diff --git a/src/output/plugins/AlsaOutputPlugin.cxx b/src/output/plugins/AlsaOutputPlugin.cxx
index 26a46ff53..088fc6c0c 100644
--- a/src/output/plugins/AlsaOutputPlugin.cxx
+++ b/src/output/plugins/AlsaOutputPlugin.cxx
@@ -774,6 +774,9 @@ AlsaOutput::Recover(int err)
if (err == -EAGAIN)
return 0;
/* fall-through to snd_pcm_prepare: */
+#if GCC_CHECK_VERSION(7,0)
+ [[fallthrough]];
+#endif
case SND_PCM_STATE_SETUP:
case SND_PCM_STATE_XRUN:
period_position = 0;
diff --git a/src/output/plugins/WinmmOutputPlugin.cxx b/src/output/plugins/WinmmOutputPlugin.cxx
index f5dac2452..1d59b891a 100644
--- a/src/output/plugins/WinmmOutputPlugin.cxx
+++ b/src/output/plugins/WinmmOutputPlugin.cxx
@@ -161,10 +161,10 @@ WinmmOutput::Open(AudioFormat &audio_format)
throw std::runtime_error("CreateEvent() failed");
switch (audio_format.format) {
- case SampleFormat::S8:
case SampleFormat::S16:
break;
+ case SampleFormat::S8:
case SampleFormat::S24_P32:
case SampleFormat::S32:
case SampleFormat::FLOAT: