diff options
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 11 | ||||
-rw-r--r-- | NEWS | 8 | ||||
-rw-r--r-- | src/decoder/DecoderAPI.cxx | 4 | ||||
-rw-r--r-- | src/decoder/DecoderInternal.cxx | 3 | ||||
-rw-r--r-- | src/decoder/DecoderThread.cxx | 12 | ||||
-rw-r--r-- | src/decoder/plugins/FfmpegDecoderPlugin.cxx | 13 | ||||
-rw-r--r-- | src/protocol/ArgParser.cxx | 4 | ||||
-rw-r--r-- | test/test_protocol.cxx | 60 |
9 files changed, 113 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore index 4e262ff2e..cf130ad92 100644 --- a/.gitignore +++ b/.gitignore @@ -64,6 +64,7 @@ tags /test/tmp /test/run_inotify /test/test_queue_priority +/test/test_protocol /test/run_ntp_server /test/run_resolver /test/run_tcp_connect diff --git a/Makefile.am b/Makefile.am index 0e3b871e7..9e04def44 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1458,6 +1458,7 @@ C_TESTS = \ test/test_rewind \ test/test_mixramp \ test/test_pcm \ + test/test_protocol \ test/test_queue_priority if ENABLE_CURL @@ -2035,6 +2036,16 @@ test_test_translate_song_LDADD = \ endif +test_test_protocol_SOURCES = \ + src/protocol/ArgParser.cxx \ + test/test_protocol.cxx +test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0 +test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations +test_test_protocol_LDADD = \ + libsystem.a \ + libutil.a \ + $(CPPUNIT_LIBS) + test_test_queue_priority_SOURCES = \ src/queue/Queue.cxx \ src/DetachedSong.cxx \ @@ -69,6 +69,14 @@ ver 0.19 (not yet released) * install systemd unit for socket activation * Android port +ver 0.18.14 (2014/09/11) +* protocol + - fix range parser bug on certain 32 bit architectures +* decoder + - audiofile: fix crash after seeking + - ffmpeg: fix crash with ffmpeg/libav version 11 + - fix assertion failure after seeking + ver 0.18.13 (2014/08/31) * protocol - don't change song on "seekcur" in random mode diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx index c3cbb3a21..4794d60e7 100644 --- a/src/decoder/DecoderAPI.cxx +++ b/src/decoder/DecoderAPI.cxx @@ -48,6 +48,7 @@ decoder_initialized(Decoder &decoder, assert(dc.state == DecoderState::START); assert(dc.pipe != nullptr); + assert(dc.pipe->IsEmpty()); assert(decoder.convert == nullptr); assert(decoder.stream_tag == nullptr); assert(decoder.decoder_tag == nullptr); @@ -461,6 +462,9 @@ decoder_data(Decoder &decoder, length == 0) return cmd; + assert(!decoder.initial_seek_pending); + assert(!decoder.initial_seek_running); + /* send stream tags */ if (update_stream_tag(decoder, is)) { diff --git a/src/decoder/DecoderInternal.cxx b/src/decoder/DecoderInternal.cxx index 416a75b75..f35878682 100644 --- a/src/decoder/DecoderInternal.cxx +++ b/src/decoder/DecoderInternal.cxx @@ -85,6 +85,9 @@ Decoder::GetChunk() void Decoder::FlushChunk() { + assert(!seeking); + assert(!initial_seek_running); + assert(!initial_seek_pending); assert(chunk != nullptr); if (chunk->IsEmpty()) diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx index 3f4f7c42e..b2b41b661 100644 --- a/src/decoder/DecoderThread.cxx +++ b/src/decoder/DecoderThread.cxx @@ -25,6 +25,7 @@ #include "DecoderPlugin.hxx" #include "DetachedSong.hxx" #include "system/FatalError.hxx" +#include "MusicPipe.hxx" #include "fs/Traits.hxx" #include "fs/AllocatedPath.hxx" #include "DecoderAPI.hxx" @@ -449,9 +450,18 @@ decoder_task(void *arg) dc.replay_gain_prev_db = dc.replay_gain_db; dc.replay_gain_db = 0; - /* fall through */ + decoder_run(dc); + break; case DecoderCommand::SEEK: + /* this seek was too late, and the decoder had + already finished; start a new decoder */ + + /* we need to clear the pipe here; usually the + PlayerThread is responsible, but it is not + aware that the decoder has finished */ + dc.pipe->Clear(*dc.buffer); + decoder_run(dc); break; diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx index 7f4ac8bcc..904e21a5a 100644 --- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx +++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx @@ -412,10 +412,23 @@ ffmpeg_probe(Decoder *decoder, InputStream &is) nbytes -= PADDING; AVProbeData avpd; + + /* new versions of ffmpeg may add new attributes, and leaving + them uninitialized may crash; hopefully, zero-initializing + everything we don't know is ok */ + memset(&avpd, 0, sizeof(avpd)); + avpd.buf = buffer; avpd.buf_size = nbytes; avpd.filename = is.GetURI(); +#ifdef AVPROBE_SCORE_MIME + /* this attribute was added in libav/ffmpeg version 11, but + unfortunately it's "uint8_t" instead of "char", and it's + not "const" - wtf? */ + avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType()); +#endif + return av_probe_input_format(&avpd, true); } diff --git a/src/protocol/ArgParser.cxx b/src/protocol/ArgParser.cxx index e3a0c107c..e373827b4 100644 --- a/src/protocol/ArgParser.cxx +++ b/src/protocol/ArgParser.cxx @@ -82,7 +82,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2, /* compatibility with older MPD versions: specifying "-1" makes MPD display the whole list */ *value_r1 = 0; - *value_r2 = std::numeric_limits<unsigned>::max(); + *value_r2 = std::numeric_limits<int>::max(); return true; } @@ -109,7 +109,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2, } if (test == test2) - value = std::numeric_limits<unsigned>::max(); + value = std::numeric_limits<int>::max(); if (value < 0) { command_error(client, ACK_ERROR_ARG, diff --git a/test/test_protocol.cxx b/test/test_protocol.cxx new file mode 100644 index 000000000..d7ea7cd87 --- /dev/null +++ b/test/test_protocol.cxx @@ -0,0 +1,60 @@ +#include "config.h" +#include "protocol/ArgParser.hxx" +#include "protocol/Result.hxx" +#include "Compiler.h" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> +#include <cppunit/extensions/HelperMacros.h> + +static enum ack last_error = ack(-1); + +void +command_error(gcc_unused Client &client, enum ack error, + gcc_unused const char *fmt, ...) +{ + last_error = error; +} + +class ArgParserTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(ArgParserTest); + CPPUNIT_TEST(TestRange); + CPPUNIT_TEST_SUITE_END(); + +public: + void TestRange(); +}; + +void +ArgParserTest::TestRange() +{ + Client &client = *(Client *)nullptr; + unsigned a, b; + + CPPUNIT_ASSERT(check_range(client, &a, &b, "1")); + CPPUNIT_ASSERT_EQUAL(1u, a); + CPPUNIT_ASSERT_EQUAL(2u, b); + + CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5")); + CPPUNIT_ASSERT_EQUAL(1u, a); + CPPUNIT_ASSERT_EQUAL(5u, b); + + CPPUNIT_ASSERT(check_range(client, &a, &b, "1:")); + CPPUNIT_ASSERT_EQUAL(1u, a); + CPPUNIT_ASSERT(b >= 999999u); + + CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2")); + CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest); + +int +main(gcc_unused int argc, gcc_unused char **argv) +{ + CppUnit::TextUi::TestRunner runner; + auto ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + runner.addTest(registry.makeTest()); + return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE; +} |