diff options
Diffstat (limited to '')
49 files changed, 1736 insertions, 1042 deletions
diff --git a/test/.gitignore b/test/.gitignore new file mode 100644 index 000000000..132ce5fcf --- /dev/null +++ b/test/.gitignore @@ -0,0 +1 @@ +/run_neighbor_explorer diff --git a/test/DumpDatabase.cxx b/test/DumpDatabase.cxx index 21a12d294..d5b6f2223 100644 --- a/test/DumpDatabase.cxx +++ b/test/DumpDatabase.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 @@ -18,16 +18,19 @@ */ #include "config.h" -#include "DatabaseRegistry.hxx" -#include "DatabasePlugin.hxx" -#include "DatabaseSelection.hxx" -#include "Directory.hxx" -#include "Song.hxx" -#include "PlaylistVector.hxx" -#include "ConfigGlobal.hxx" -#include "ConfigData.hxx" +#include "db/Registry.hxx" +#include "db/DatabasePlugin.hxx" +#include "db/Interface.hxx" +#include "db/Selection.hxx" +#include "db/DatabaseListener.hxx" +#include "db/LightDirectory.hxx" +#include "db/LightSong.hxx" +#include "db/PlaylistVector.hxx" +#include "config/ConfigGlobal.hxx" +#include "config/ConfigData.hxx" #include "tag/TagConfig.hxx" #include "fs/Path.hxx" +#include "event/Loop.hxx" #include "util/Error.hxx" #include <glib.h> @@ -39,35 +42,49 @@ using std::endl; #include <stdlib.h> -static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) +#ifdef HAVE_LIBUPNP +#include "input/InputStream.hxx" +size_t +InputStream::LockRead(void *, size_t, Error &) { - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); + return 0; } +#endif + +class MyDatabaseListener final : public DatabaseListener { +public: + virtual void OnDatabaseModified() override { + cout << "DatabaseModified" << endl; + } + + virtual void OnDatabaseSongRemoved(const LightSong &song) override { + cout << "SongRemoved " << song.GetURI() << endl; + } +}; static bool -DumpDirectory(const Directory &directory, Error &) +DumpDirectory(const LightDirectory &directory, Error &) { - cout << "D " << directory.path << endl; + cout << "D " << directory.GetPath() << endl; return true; } static bool -DumpSong(Song &song, Error &) +DumpSong(const LightSong &song, Error &) { - cout << "S " << song.parent->path << "/" << song.uri << endl; + cout << "S "; + if (song.directory != nullptr) + cout << song.directory << "/"; + cout << song.uri << endl; return true; } static bool DumpPlaylist(const PlaylistInfo &playlist, - const Directory &directory, Error &) + const LightDirectory &directory, Error &) { - cout << "P " << directory.path << "/" << playlist.name.c_str() << endl; + cout << "P " << directory.GetPath() + << "/" << playlist.name.c_str() << endl; return true; } @@ -94,8 +111,6 @@ main(int argc, char **argv) g_thread_init(nullptr); #endif - g_log_set_default_handler(my_log_func, nullptr); - /* initialize MPD */ config_global_init(); @@ -108,14 +123,18 @@ main(int argc, char **argv) TagLoadConfig(); + EventLoop event_loop; + MyDatabaseListener database_listener; + /* do it */ const struct config_param *path = config_get_param(CONF_DB_FILE); - config_param param("database", path->line); + config_param param("database", path != nullptr ? path->line : -1); if (path != nullptr) param.AddBlockParam("path", path->value.c_str(), path->line); - Database *db = plugin->create(param, error); + Database *db = plugin->create(event_loop, database_listener, + param, error); if (db == nullptr) { cerr << error.GetMessage() << endl; diff --git a/test/FakeDecoderAPI.cxx b/test/FakeDecoderAPI.cxx index ca09ca982..dcc78125b 100644 --- a/test/FakeDecoderAPI.cxx +++ b/test/FakeDecoderAPI.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2012 The Music Player Daemon Project + * 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 @@ -18,21 +18,30 @@ */ #include "config.h" -#include "DecoderAPI.hxx" -#include "InputStream.hxx" +#include "FakeDecoderAPI.hxx" +#include "decoder/DecoderAPI.hxx" +#include "input/InputStream.hxx" #include "util/Error.hxx" #include "Compiler.h" -#include <glib.h> - #include <unistd.h> void -decoder_initialized(gcc_unused Decoder &decoder, - gcc_unused const AudioFormat audio_format, +decoder_initialized(Decoder &decoder, + const AudioFormat audio_format, gcc_unused bool seekable, - gcc_unused float total_time) + SignedSongTime duration) { + struct audio_format_string af_string; + + assert(!decoder.initialized); + assert(audio_format.IsValid()); + + fprintf(stderr, "audio_format=%s duration=%f\n", + audio_format_to_string(audio_format, &af_string), + duration.ToDoubleS()); + + decoder.initialized = true; } DecoderCommand @@ -46,10 +55,16 @@ decoder_command_finished(gcc_unused Decoder &decoder) { } -double -decoder_seek_where(gcc_unused Decoder &decoder) +SongTime +decoder_seek_time(gcc_unused Decoder &decoder) +{ + return SongTime(); +} + +uint64_t +decoder_seek_where_frame(gcc_unused Decoder &decoder) { - return 1.0; + return 1; } void @@ -57,6 +72,12 @@ decoder_seek_error(gcc_unused Decoder &decoder) { } +InputStream * +decoder_open_uri(Decoder &decoder, const char *uri, Error &error) +{ + return InputStream::OpenReady(uri, decoder.mutex, decoder.cond, error); +} + size_t decoder_read(gcc_unused Decoder *decoder, InputStream &is, @@ -129,16 +150,18 @@ decoder_replay_gain(gcc_unused Decoder &decoder, { const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM]; if (tuple->IsDefined()) - g_printerr("replay_gain[album]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); + fprintf(stderr, "replay_gain[album]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); tuple = &rgi->tuples[REPLAY_GAIN_TRACK]; if (tuple->IsDefined()) - g_printerr("replay_gain[track]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); + fprintf(stderr, "replay_gain[track]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); } void decoder_mixramp(gcc_unused Decoder &decoder, gcc_unused MixRampInfo &&mix_ramp) { + fprintf(stderr, "MixRamp: start='%s' end='%s'\n", + mix_ramp.GetStart(), mix_ramp.GetEnd()); } diff --git a/test/FakeDecoderAPI.hxx b/test/FakeDecoderAPI.hxx new file mode 100644 index 000000000..6f1933977 --- /dev/null +++ b/test/FakeDecoderAPI.hxx @@ -0,0 +1,37 @@ +/* + * 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 FAKE_DECODER_API_HXX +#define FAKE_DECODER_API_HXX + +#include "check.h" +#include "thread/Mutex.hxx" +#include "thread/Cond.hxx" + +struct Decoder { + Mutex mutex; + Cond cond; + + bool initialized; + + Decoder() + :initialized(false) {} +}; + +#endif diff --git a/test/FakeReplayGainConfig.cxx b/test/FakeReplayGainConfig.cxx index 3305b79a3..0cb282050 100644 --- a/test/FakeReplayGainConfig.cxx +++ b/test/FakeReplayGainConfig.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 diff --git a/test/FakeSong.cxx b/test/FakeSong.cxx deleted file mode 100644 index c0859d7b1..000000000 --- a/test/FakeSong.cxx +++ /dev/null @@ -1,33 +0,0 @@ -/* - * Copyright (C) 2003-2012 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. - */ - -#include "config.h" -#include "Song.hxx" -#include "directory.h" -#include "Compiler.h" - -#include <stdlib.h> - -struct directory detached_root; - -Song * -song_dup_detached(gcc_unused const Song *src) -{ - abort(); -} diff --git a/test/ShutdownHandler.cxx b/test/ShutdownHandler.cxx index 341a92939..c04834444 100644 --- a/test/ShutdownHandler.cxx +++ b/test/ShutdownHandler.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 diff --git a/test/ShutdownHandler.hxx b/test/ShutdownHandler.hxx index 0a84ed63f..9db88a1b4 100644 --- a/test/ShutdownHandler.hxx +++ b/test/ShutdownHandler.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -24,7 +24,7 @@ class EventLoop; class ShutdownHandler { public: - ShutdownHandler(EventLoop &loop); + explicit ShutdownHandler(EventLoop &loop); ~ShutdownHandler(); }; diff --git a/test/TestCircularBuffer.hxx b/test/TestCircularBuffer.hxx new file mode 100644 index 000000000..c808d85dc --- /dev/null +++ b/test/TestCircularBuffer.hxx @@ -0,0 +1,163 @@ +/* + * Unit tests for class CircularBuffer. + */ + +#include "config.h" +#include "util/CircularBuffer.hxx" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <string.h> +#include <stdlib.h> + +class TestCircularBuffer : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TestCircularBuffer); + CPPUNIT_TEST(TestIt); + CPPUNIT_TEST_SUITE_END(); + +public: + void TestIt() { + static size_t N = 8; + int data[N]; + CircularBuffer<int> buffer(data, N); + + CPPUNIT_ASSERT_EQUAL(size_t(N), buffer.GetCapacity()); + + /* '.' = empty; 'O' = occupied; 'X' = blocked */ + + /* checks on empty buffer */ + /* [.......X] */ + CPPUNIT_ASSERT_EQUAL(true, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(true, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Write().size); + + /* append one element */ + /* [O......X] */ + buffer.Append(1); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.Write().size); + + /* append 6 elements, buffer is now full */ + /* [OOOOOOOX] */ + buffer.Append(6); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty()); + + /* consume [0]; can append one at [7] */ + /* [XOOOOOO.] */ + buffer.Consume(1); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[7], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Write().size); + + /* append one element; [0] is still empty but cannot + be written to because head==1 */ + /* [XOOOOOOO] */ + buffer.Append(1); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[1], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty()); + + /* consume [1..3]; can append [0..2] */ + /* [...XOOOO] */ + buffer.Consume(3); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.Write().size); + + /* append [0..1] */ + /* [OO.XOOOO] */ + buffer.Append(2); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(6), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[2], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(1), buffer.Write().size); + + /* append [2] */ + /* [OOOXOOOO] */ + buffer.Append(1); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(true, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[4], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(true, buffer.Write().IsEmpty()); + + /* consume [4..7] */ + /* [OOO....X] */ + buffer.Consume(4); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(size_t(3), buffer.Read().size); + CPPUNIT_ASSERT_EQUAL(&data[0], buffer.Read().data); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[3], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(4), buffer.Write().size); + + /* consume [0..2]; after that, we can only write 5, + because the CircularBuffer class doesn't have + special code to rewind/reset an empty buffer */ + /* [..X.....] */ + buffer.Consume(3); + CPPUNIT_ASSERT_EQUAL(true, buffer.IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.IsFull()); + CPPUNIT_ASSERT_EQUAL(size_t(0), buffer.GetSize()); + CPPUNIT_ASSERT_EQUAL(size_t(7), buffer.GetSpace()); + CPPUNIT_ASSERT_EQUAL(true, buffer.Read().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(false, buffer.Write().IsEmpty()); + CPPUNIT_ASSERT_EQUAL(&data[3], buffer.Write().data); + CPPUNIT_ASSERT_EQUAL(size_t(5), buffer.Write().size); + } +}; diff --git a/test/dump_playlist.cxx b/test/dump_playlist.cxx index 4ac02985a..6205c8a79 100644 --- a/test/dump_playlist.cxx +++ b/test/dump_playlist.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -19,48 +19,46 @@ #include "config.h" #include "TagSave.hxx" -#include "Song.hxx" -#include "SongEnumerator.hxx" -#include "Directory.hxx" -#include "InputStream.hxx" -#include "ConfigGlobal.hxx" -#include "DecoderList.hxx" -#include "InputInit.hxx" +#include "DetachedSong.hxx" +#include "playlist/SongEnumerator.hxx" +#include "input/InputStream.hxx" +#include "config/ConfigGlobal.hxx" +#include "decoder/DecoderList.hxx" +#include "input/Init.hxx" #include "IOThread.hxx" -#include "PlaylistRegistry.hxx" -#include "PlaylistPlugin.hxx" +#include "playlist/PlaylistRegistry.hxx" +#include "playlist/PlaylistPlugin.hxx" #include "fs/Path.hxx" +#include "fs/io/BufferedOutputStream.hxx" +#include "fs/io/StdioOutputStream.hxx" #include "util/Error.hxx" #include "thread/Cond.hxx" #include "Log.hxx" +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <unistd.h> #include <stdlib.h> -Directory::Directory() {} -Directory::~Directory() {} - static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) +tag_save(FILE *file, const Tag &tag) { - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); + StdioOutputStream sos(file); + BufferedOutputStream bos(sos); + tag_save(bos, tag); + bos.Flush(); } int main(int argc, char **argv) { const char *uri; InputStream *is = NULL; - Song *song; if (argc != 3) { - g_printerr("Usage: dump_playlist CONFIG URI\n"); - return 1; + fprintf(stderr, "Usage: dump_playlist CONFIG URI\n"); + return EXIT_FAILURE; } const Path config_path = Path::FromFS(argv[1]); @@ -68,11 +66,11 @@ int main(int argc, char **argv) /* initialize GLib */ +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - - g_log_set_default_handler(my_log_func, NULL); +#endif /* initialize MPD */ @@ -80,8 +78,8 @@ int main(int argc, char **argv) Error error; if (!ReadConfigFile(config_path, error)) { - g_printerr("%s\n", error.GetMessage()); - return 1; + LogError(error); + return EXIT_FAILURE; } io_thread_init(); @@ -89,7 +87,7 @@ int main(int argc, char **argv) if (!input_stream_global_init(error)) { LogError(error); - return 2; + return EXIT_FAILURE; } playlist_list_global_init(); @@ -104,54 +102,55 @@ int main(int argc, char **argv) if (playlist == NULL) { /* open the stream and wait until it becomes ready */ - is = InputStream::Open(uri, mutex, cond, error); + is = InputStream::OpenReady(uri, mutex, cond, error); if (is == NULL) { if (error.IsDefined()) LogError(error); else - g_printerr("InputStream::Open() failed\n"); + fprintf(stderr, + "InputStream::Open() failed\n"); return 2; } - is->LockWaitReady(); - /* open the playlist */ playlist = playlist_list_open_stream(*is, uri); if (playlist == NULL) { - is->Close(); - g_printerr("Failed to open playlist\n"); + delete is; + fprintf(stderr, "Failed to open playlist\n"); return 2; } } /* dump the playlist */ + DetachedSong *song; while ((song = playlist->NextSong()) != NULL) { - g_print("%s\n", song->uri); - - if (song->end_ms > 0) - g_print("range: %u:%02u..%u:%02u\n", - song->start_ms / 60000, - (song->start_ms / 1000) % 60, - song->end_ms / 60000, - (song->end_ms / 1000) % 60); - else if (song->start_ms > 0) - g_print("range: %u:%02u..\n", - song->start_ms / 60000, - (song->start_ms / 1000) % 60); - - if (song->tag != NULL) - tag_save(stdout, *song->tag); - - song->Free(); + printf("%s\n", song->GetURI()); + + const unsigned start_ms = song->GetStartTime().ToMS(); + const unsigned end_ms = song->GetEndTime().ToMS(); + + if (end_ms > 0) + printf("range: %u:%02u..%u:%02u\n", + start_ms / 60000, + (start_ms / 1000) % 60, + end_ms / 60000, + (end_ms / 1000) % 60); + else if (start_ms > 0) + printf("range: %u:%02u..\n", + start_ms / 60000, + (start_ms / 1000) % 60); + + tag_save(stdout, song->GetTag()); + + delete song; } /* deinitialize everything */ delete playlist; - if (is != NULL) - is->Close(); + delete is; decoder_plugin_deinit_all(); playlist_list_global_finish(); diff --git a/test/dump_rva2.cxx b/test/dump_rva2.cxx index e1ba5336a..fd46ee36c 100644 --- a/test/dump_rva2.cxx +++ b/test/dump_rva2.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -21,19 +21,19 @@ #include "tag/TagId3.hxx" #include "tag/TagRva2.hxx" #include "ReplayGainInfo.hxx" -#include "ConfigGlobal.hxx" +#include "config/ConfigGlobal.hxx" #include "util/Error.hxx" #include "fs/Path.hxx" +#include "Log.hxx" #include <id3tag.h> -#include <glib.h> - #ifdef HAVE_LOCALE_H #include <locale.h> #endif #include <stdlib.h> +#include <stdio.h> const char * config_get_string(gcc_unused enum ConfigOption option, @@ -50,8 +50,8 @@ int main(int argc, char **argv) #endif if (argc != 2) { - g_printerr("Usage: read_rva2 FILE\n"); - return 1; + fprintf(stderr, "Usage: read_rva2 FILE\n"); + return EXIT_FAILURE; } const char *path = argv[1]; @@ -60,9 +60,9 @@ int main(int argc, char **argv) struct id3_tag *tag = tag_id3_load(Path::FromFS(path), error); if (tag == NULL) { if (error.IsDefined()) - g_printerr("%s\n", error.GetMessage()); + LogError(error); else - g_printerr("No ID3 tag found\n"); + fprintf(stderr, "No ID3 tag found\n"); return EXIT_FAILURE; } @@ -74,19 +74,19 @@ int main(int argc, char **argv) id3_tag_delete(tag); if (!success) { - g_printerr("No RVA2 tag found\n"); + fprintf(stderr, "No RVA2 tag found\n"); return EXIT_FAILURE; } const ReplayGainTuple *tuple = &replay_gain.tuples[REPLAY_GAIN_ALBUM]; if (tuple->IsDefined()) - g_printerr("replay_gain[album]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); + fprintf(stderr, "replay_gain[album]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); tuple = &replay_gain.tuples[REPLAY_GAIN_TRACK]; if (tuple->IsDefined()) - g_printerr("replay_gain[track]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); + fprintf(stderr, "replay_gain[track]: gain=%f peak=%f\n", + tuple->gain, tuple->peak); return EXIT_SUCCESS; } diff --git a/test/dump_text_file.cxx b/test/dump_text_file.cxx index bb84f5cce..03f8114a4 100644 --- a/test/dump_text_file.cxx +++ b/test/dump_text_file.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -19,63 +19,38 @@ #include "config.h" #include "IOThread.hxx" -#include "InputInit.hxx" -#include "InputStream.hxx" -#include "ConfigGlobal.hxx" +#include "input/Init.hxx" +#include "input/InputStream.hxx" +#include "input/TextInputStream.hxx" +#include "config/ConfigGlobal.hxx" #include "stdbin.h" -#include "TextInputStream.hxx" #include "util/Error.hxx" #include "thread/Cond.hxx" #include "Log.hxx" #ifdef ENABLE_ARCHIVE -#include "ArchiveList.hxx" +#include "archive/ArchiveList.hxx" #endif +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <unistd.h> #include <stdio.h> #include <stdlib.h> static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - -static void dump_text_file(TextInputStream &is) { - std::string line; - while (is.ReadLine(line)) - printf("'%s'\n", line.c_str()); + const char *line; + while ((line = is.ReadLine()) != nullptr) + printf("'%s'\n", line); } static int dump_input_stream(InputStream &is) { - Error error; - - is.Lock(); - - /* wait until the stream becomes ready */ - - is.WaitReady(); - - if (!is.Check(error)) { - LogError(error); - is.Unlock(); - return EXIT_FAILURE; - } - - /* read data and tags from the stream */ - - is.Unlock(); { TextInputStream tis(is); dump_text_file(tis); @@ -83,6 +58,7 @@ dump_input_stream(InputStream &is) is.Lock(); + Error error; if (!is.Check(error)) { LogError(error); is.Unlock(); @@ -99,17 +75,17 @@ int main(int argc, char **argv) int ret; if (argc != 2) { - g_printerr("Usage: run_input URI\n"); - return 1; + fprintf(stderr, "Usage: run_input URI\n"); + return EXIT_FAILURE; } /* initialize GLib */ +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - - g_log_set_default_handler(my_log_func, NULL); +#endif /* initialize MPD */ @@ -133,16 +109,16 @@ int main(int argc, char **argv) Mutex mutex; Cond cond; - InputStream *is = InputStream::Open(argv[1], mutex, cond, error); + InputStream *is = InputStream::OpenReady(argv[1], mutex, cond, error); if (is != NULL) { ret = dump_input_stream(*is); - is->Close(); + delete is; } else { if (error.IsDefined()) LogError(error); else - g_printerr("input_stream::Open() failed\n"); - ret = 2; + fprintf(stderr, "input_stream::Open() failed\n"); + ret = EXIT_FAILURE; } /* deinitialize everything */ diff --git a/test/read_conf.cxx b/test/read_conf.cxx index d5eacec67..42afdfb4b 100644 --- a/test/read_conf.cxx +++ b/test/read_conf.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -18,43 +18,31 @@ */ #include "config.h" -#include "ConfigGlobal.hxx" +#include "config/ConfigGlobal.hxx" #include "fs/Path.hxx" #include "util/Error.hxx" - -#include <glib.h> +#include "Log.hxx" #include <assert.h> - -static void -my_log_func(gcc_unused const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_level > G_LOG_LEVEL_WARNING) - return; - - g_printerr("%s\n", message); -} +#include <stdio.h> +#include <stdlib.h> int main(int argc, char **argv) { if (argc != 3) { - g_printerr("Usage: read_conf FILE SETTING\n"); - return 1; + fprintf(stderr, "Usage: read_conf FILE SETTING\n"); + return EXIT_FAILURE; } const Path config_path = Path::FromFS(argv[1]); const char *name = argv[2]; - g_log_set_default_handler(my_log_func, NULL); - config_global_init(); Error error; if (!ReadConfigFile(config_path, error)) { - g_printerr("%s:", error.GetMessage()); - return 1; + LogError(error); + return EXIT_FAILURE; } ConfigOption option = ParseConfigOptionName(name); @@ -63,11 +51,11 @@ int main(int argc, char **argv) : nullptr; int ret; if (value != NULL) { - g_print("%s\n", value); - ret = 0; + printf("%s\n", value); + ret = EXIT_SUCCESS; } else { - g_printerr("No such setting: %s\n", name); - ret = 2; + fprintf(stderr, "No such setting: %s\n", name); + ret = EXIT_FAILURE; } config_global_finish(); diff --git a/test/read_mixer.cxx b/test/read_mixer.cxx index 8426443ae..97529057f 100644 --- a/test/read_mixer.cxx +++ b/test/read_mixer.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -18,15 +18,15 @@ */ #include "config.h" -#include "MixerControl.hxx" -#include "MixerList.hxx" -#include "FilterRegistry.hxx" -#include "pcm/PcmVolume.hxx" -#include "GlobalEvents.hxx" +#include "mixer/MixerControl.hxx" +#include "mixer/MixerList.hxx" +#include "filter/FilterRegistry.hxx" +#include "pcm/Volume.hxx" #include "Main.hxx" #include "event/Loop.hxx" -#include "ConfigData.hxx" +#include "config/ConfigData.hxx" #include "util/Error.hxx" +#include "Log.hxx" #include <glib.h> @@ -34,66 +34,6 @@ #include <string.h> #include <unistd.h> -EventLoop *main_loop; - -#ifdef HAVE_PULSE -#include "output/PulseOutputPlugin.hxx" - -void -pulse_output_lock(gcc_unused PulseOutput *po) -{ -} - -void -pulse_output_unlock(gcc_unused PulseOutput *po) -{ -} - -void -pulse_output_set_mixer(gcc_unused PulseOutput *po, - gcc_unused PulseMixer *pm) -{ -} - -void -pulse_output_clear_mixer(gcc_unused PulseOutput *po, - gcc_unused PulseMixer *pm) -{ -} - -bool -pulse_output_set_volume(gcc_unused PulseOutput *po, - gcc_unused const struct pa_cvolume *volume, - gcc_unused Error &error) -{ - return false; -} - -#endif - -#ifdef HAVE_ROAR -#include "output/RoarOutputPlugin.hxx" - -int -roar_output_get_volume(gcc_unused RoarOutput *roar) -{ - return -1; -} - -bool -roar_output_set_volume(gcc_unused RoarOutput *roar, - gcc_unused unsigned volume) -{ - return true; -} - -#endif - -void -GlobalEvents::Emit(gcc_unused Event event) -{ -} - const struct filter_plugin * filter_plugin_by_name(gcc_unused const char *name) { @@ -101,61 +41,51 @@ filter_plugin_by_name(gcc_unused const char *name) return NULL; } -bool -pcm_volume(gcc_unused void *buffer, gcc_unused size_t length, - gcc_unused SampleFormat format, - gcc_unused int volume) -{ - assert(false); - return false; -} - int main(int argc, gcc_unused char **argv) { int volume; if (argc != 2) { - g_printerr("Usage: read_mixer PLUGIN\n"); - return 1; + fprintf(stderr, "Usage: read_mixer PLUGIN\n"); + return EXIT_FAILURE; } #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - main_loop = new EventLoop(EventLoop::Default()); + EventLoop event_loop; Error error; - Mixer *mixer = mixer_new(&alsa_mixer_plugin, nullptr, + Mixer *mixer = mixer_new(event_loop, alsa_mixer_plugin, + *(AudioOutput *)nullptr, + *(MixerListener *)nullptr, config_param(), error); if (mixer == NULL) { - g_printerr("mixer_new() failed: %s\n", error.GetMessage()); - return 2; + LogError(error, "mixer_new() failed"); + return EXIT_FAILURE; } if (!mixer_open(mixer, error)) { mixer_free(mixer); - g_printerr("failed to open the mixer: %s\n", error.GetMessage()); - return 2; + LogError(error, "failed to open the mixer"); + return EXIT_FAILURE; } volume = mixer_get_volume(mixer, error); mixer_close(mixer); mixer_free(mixer); - delete main_loop; - assert(volume >= -1 && volume <= 100); if (volume < 0) { if (error.IsDefined()) { - g_printerr("failed to read volume: %s\n", - error.GetMessage()); + LogError(error, "failed to read volume"); } else - g_printerr("failed to read volume\n"); - return 2; + fprintf(stderr, "failed to read volume\n"); + return EXIT_FAILURE; } - g_print("%d\n", volume); + printf("%d\n", volume); return 0; } diff --git a/test/read_tags.cxx b/test/read_tags.cxx index 52b2561b8..67962062c 100644 --- a/test/read_tags.cxx +++ b/test/read_tags.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -19,10 +19,10 @@ #include "config.h" #include "IOThread.hxx" -#include "DecoderList.hxx" -#include "DecoderPlugin.hxx" -#include "InputInit.hxx" -#include "InputStream.hxx" +#include "decoder/DecoderList.hxx" +#include "decoder/DecoderPlugin.hxx" +#include "input/Init.hxx" +#include "input/InputStream.hxx" #include "AudioFormat.hxx" #include "tag/TagHandler.hxx" #include "tag/TagId3.hxx" @@ -32,11 +32,14 @@ #include "thread/Cond.hxx" #include "Log.hxx" +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <assert.h> #include <unistd.h> #include <stdlib.h> +#include <stdio.h> #ifdef HAVE_LOCALE_H #include <locale.h> @@ -45,22 +48,22 @@ static bool empty = true; static void -print_duration(unsigned seconds, gcc_unused void *ctx) +print_duration(SongTime duration, gcc_unused void *ctx) { - g_print("duration=%d\n", seconds); + printf("duration=%f\n", duration.ToDoubleS()); } static void print_tag(TagType type, const char *value, gcc_unused void *ctx) { - g_print("[%s]=%s\n", tag_item_names[type], value); + printf("[%s]=%s\n", tag_item_names[type], value); empty = false; } static void print_pair(const char *name, const char *value, gcc_unused void *ctx) { - g_print("\"%s\"=%s\n", name, value); + printf("\"%s\"=%s\n", name, value); } static const struct tag_handler print_handler = { @@ -71,7 +74,7 @@ static const struct tag_handler print_handler = { int main(int argc, char **argv) { - const char *decoder_name, *path; + const char *decoder_name; const struct DecoderPlugin *plugin; #ifdef HAVE_LOCALE_H @@ -80,16 +83,18 @@ int main(int argc, char **argv) #endif if (argc != 3) { - g_printerr("Usage: read_tags DECODER FILE\n"); - return 1; + fprintf(stderr, "Usage: read_tags DECODER FILE\n"); + return EXIT_FAILURE; } decoder_name = argv[1]; - path = argv[2]; + const Path path = Path::FromFS(argv[2]); +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif +#endif io_thread_init(); io_thread_start(); @@ -104,8 +109,8 @@ int main(int argc, char **argv) plugin = decoder_plugin_from_name(decoder_name); if (plugin == NULL) { - g_printerr("No such decoder: %s\n", decoder_name); - return 1; + fprintf(stderr, "No such decoder: %s\n", decoder_name); + return EXIT_FAILURE; } bool success = plugin->ScanFile(path, print_handler, nullptr); @@ -113,30 +118,16 @@ int main(int argc, char **argv) Mutex mutex; Cond cond; - InputStream *is = InputStream::Open(path, mutex, cond, - error); + InputStream *is = InputStream::OpenReady(path.c_str(), + mutex, cond, + error); if (is == NULL) { - g_printerr("Failed to open %s: %s\n", - path, error.GetMessage()); - return 1; - } - - mutex.lock(); - - is->WaitReady(); - - if (!is->Check(error)) { - mutex.unlock(); - - g_printerr("Failed to read %s: %s\n", - path, error.GetMessage()); + FormatError(error, "Failed to open %s", path.c_str()); return EXIT_FAILURE; } - mutex.unlock(); - success = plugin->ScanStream(*is, print_handler, nullptr); - is->Close(); + delete is; } decoder_plugin_deinit_all(); @@ -144,14 +135,14 @@ int main(int argc, char **argv) io_thread_deinit(); if (!success) { - g_printerr("Failed to read tags\n"); - return 1; + fprintf(stderr, "Failed to read tags\n"); + return EXIT_FAILURE; } if (empty) { - tag_ape_scan2(Path::FromFS(path), &print_handler, NULL); + tag_ape_scan2(path, &print_handler, NULL); if (empty) - tag_id3_scan(Path::FromFS(path), &print_handler, NULL); + tag_id3_scan(path, &print_handler, NULL); } return 0; diff --git a/test/run_avahi.cxx b/test/run_avahi.cxx index b392edb6d..b3b20365c 100644 --- a/test/run_avahi.cxx +++ b/test/run_avahi.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -20,7 +20,7 @@ #include "config.h" #include "event/Loop.hxx" #include "ShutdownHandler.hxx" -#include "ZeroconfAvahi.hxx" +#include "zeroconf/ZeroconfAvahi.hxx" #include <stdlib.h> @@ -29,7 +29,7 @@ unsigned listen_port = 1234; int main(gcc_unused int argc, gcc_unused char **argv) { - EventLoop event_loop((EventLoop::Default())); + EventLoop event_loop; const ShutdownHandler shutdown_handler(event_loop); AvahiInit(event_loop, "test"); diff --git a/test/run_convert.cxx b/test/run_convert.cxx index 0e873a3b3..8b9b15cf0 100644 --- a/test/run_convert.cxx +++ b/test/run_convert.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -27,28 +27,18 @@ #include "AudioParser.hxx" #include "AudioFormat.hxx" #include "pcm/PcmConvert.hxx" -#include "ConfigGlobal.hxx" -#include "util/FifoBuffer.hxx" +#include "config/ConfigGlobal.hxx" +#include "util/ConstBuffer.hxx" +#include "util/StaticFifoBuffer.hxx" #include "util/Error.hxx" +#include "Log.hxx" #include "stdbin.h" -#include <glib.h> - #include <assert.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> -static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - const char * config_get_string(gcc_unused enum ConfigOption option, const char *default_value) @@ -59,29 +49,25 @@ config_get_string(gcc_unused enum ConfigOption option, int main(int argc, char **argv) { AudioFormat in_audio_format, out_audio_format; - const void *output; if (argc != 3) { - g_printerr("Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n"); + fprintf(stderr, + "Usage: run_convert IN_FORMAT OUT_FORMAT <IN >OUT\n"); return 1; } - g_log_set_default_handler(my_log_func, NULL); - Error error; if (!audio_format_parse(in_audio_format, argv[1], false, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } AudioFormat out_audio_format_mask; if (!audio_format_parse(out_audio_format_mask, argv[2], true, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } out_audio_format = in_audio_format; @@ -90,8 +76,12 @@ int main(int argc, char **argv) const size_t in_frame_size = in_audio_format.GetFrameSize(); PcmConvert state; + if (!state.Open(in_audio_format, out_audio_format_mask, error)) { + LogError(error, "Failed to open PcmConvert"); + return EXIT_FAILURE; + } - FifoBuffer<uint8_t, 4096> buffer; + StaticFifoBuffer<uint8_t, 4096> buffer; while (true) { { @@ -114,16 +104,18 @@ int main(int argc, char **argv) buffer.Consume(src.size); - size_t length; - output = state.Convert(in_audio_format, src.data, src.size, - out_audio_format, &length, error); - if (output == NULL) { - g_printerr("Failed to convert: %s\n", error.GetMessage()); - return 2; + auto output = state.Convert({src.data, src.size}, error); + if (output.IsNull()) { + state.Close(); + LogError(error, "Failed to convert"); + return EXIT_FAILURE; } - gcc_unused ssize_t ignored = write(1, output, length); + gcc_unused ssize_t ignored = write(1, output.data, + output.size); } + state.Close(); + return EXIT_SUCCESS; } diff --git a/test/run_decoder.cxx b/test/run_decoder.cxx index 3fbfc5521..3980340cc 100644 --- a/test/run_decoder.cxx +++ b/test/run_decoder.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -19,186 +19,42 @@ #include "config.h" #include "IOThread.hxx" -#include "DecoderList.hxx" -#include "DecoderAPI.hxx" -#include "InputInit.hxx" -#include "InputStream.hxx" +#include "decoder/DecoderList.hxx" +#include "decoder/DecoderPlugin.hxx" +#include "FakeDecoderAPI.hxx" +#include "input/Init.hxx" +#include "input/InputStream.hxx" +#include "fs/Path.hxx" #include "AudioFormat.hxx" #include "util/Error.hxx" -#include "thread/Cond.hxx" #include "Log.hxx" #include "stdbin.h" +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <assert.h> #include <unistd.h> #include <stdlib.h> - -static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - -struct Decoder { - const char *uri; - - const struct DecoderPlugin *plugin; - - bool initialized; -}; - -void -decoder_initialized(Decoder &decoder, - const AudioFormat audio_format, - gcc_unused bool seekable, - float duration) -{ - struct audio_format_string af_string; - - assert(!decoder.initialized); - assert(audio_format.IsValid()); - - g_printerr("audio_format=%s duration=%f\n", - audio_format_to_string(audio_format, &af_string), - duration); - - decoder.initialized = true; -} - -DecoderCommand -decoder_get_command(gcc_unused Decoder &decoder) -{ - return DecoderCommand::NONE; -} - -void -decoder_command_finished(gcc_unused Decoder &decoder) -{ -} - -double -decoder_seek_where(gcc_unused Decoder &decoder) -{ - return 1.0; -} - -void -decoder_seek_error(gcc_unused Decoder &decoder) -{ -} - -size_t -decoder_read(gcc_unused Decoder *decoder, - InputStream &is, - void *buffer, size_t length) -{ - return is.LockRead(buffer, length, IgnoreError()); -} - -bool -decoder_read_full(Decoder *decoder, InputStream &is, - void *_buffer, size_t size) -{ - uint8_t *buffer = (uint8_t *)_buffer; - - while (size > 0) { - size_t nbytes = decoder_read(decoder, is, buffer, size); - if (nbytes == 0) - return false; - - buffer += nbytes; - size -= nbytes; - } - - return true; -} - -bool -decoder_skip(Decoder *decoder, InputStream &is, size_t size) -{ - while (size > 0) { - char buffer[1024]; - size_t nbytes = decoder_read(decoder, is, buffer, - std::min(sizeof(buffer), size)); - if (nbytes == 0) - return false; - - size -= nbytes; - } - - return true; -} - -void -decoder_timestamp(gcc_unused Decoder &decoder, - gcc_unused double t) -{ -} - -DecoderCommand -decoder_data(gcc_unused Decoder &decoder, - gcc_unused InputStream *is, - const void *data, size_t datalen, - gcc_unused uint16_t kbit_rate) -{ - gcc_unused ssize_t nbytes = write(1, data, datalen); - return DecoderCommand::NONE; -} - -DecoderCommand -decoder_tag(gcc_unused Decoder &decoder, - gcc_unused InputStream *is, - gcc_unused Tag &&tag) -{ - return DecoderCommand::NONE; -} - -void -decoder_replay_gain(gcc_unused Decoder &decoder, - const ReplayGainInfo *rgi) -{ - const ReplayGainTuple *tuple = &rgi->tuples[REPLAY_GAIN_ALBUM]; - if (tuple->IsDefined()) - g_printerr("replay_gain[album]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); - - tuple = &rgi->tuples[REPLAY_GAIN_TRACK]; - if (tuple->IsDefined()) - g_printerr("replay_gain[track]: gain=%f peak=%f\n", - tuple->gain, tuple->peak); -} - -void -decoder_mixramp(gcc_unused Decoder &decoder, MixRampInfo &&mix_ramp) -{ - fprintf(stderr, "MixRamp: start='%s' end='%s'\n", - mix_ramp.GetStart(), mix_ramp.GetEnd()); -} +#include <stdio.h> int main(int argc, char **argv) { - const char *decoder_name; - if (argc != 3) { - g_printerr("Usage: run_decoder DECODER URI >OUT\n"); - return 1; + fprintf(stderr, "Usage: run_decoder DECODER URI >OUT\n"); + return EXIT_FAILURE; } Decoder decoder; - decoder_name = argv[1]; - decoder.uri = argv[2]; + const char *const decoder_name = argv[1]; + const char *const uri = argv[2]; +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - - g_log_set_default_handler(my_log_func, NULL); +#endif io_thread_init(); io_thread_start(); @@ -206,42 +62,38 @@ int main(int argc, char **argv) Error error; if (!input_stream_global_init(error)) { LogError(error); - return 2; + return EXIT_FAILURE; } decoder_plugin_init_all(); - decoder.plugin = decoder_plugin_from_name(decoder_name); - if (decoder.plugin == NULL) { - g_printerr("No such decoder: %s\n", decoder_name); - return 1; + const DecoderPlugin *plugin = decoder_plugin_from_name(decoder_name); + if (plugin == nullptr) { + fprintf(stderr, "No such decoder: %s\n", decoder_name); + return EXIT_FAILURE; } - decoder.initialized = false; - - if (decoder.plugin->file_decode != NULL) { - decoder.plugin->FileDecode(decoder, decoder.uri); - } else if (decoder.plugin->stream_decode != NULL) { - Mutex mutex; - Cond cond; - + if (plugin->file_decode != nullptr) { + plugin->FileDecode(decoder, Path::FromFS(uri)); + } else if (plugin->stream_decode != nullptr) { InputStream *is = - InputStream::Open(decoder.uri, mutex, cond, error); + InputStream::OpenReady(uri, decoder.mutex, + decoder.cond, error); if (is == NULL) { if (error.IsDefined()) LogError(error); else - g_printerr("InputStream::Open() failed\n"); + fprintf(stderr, "InputStream::Open() failed\n"); - return 1; + return EXIT_FAILURE; } - decoder.plugin->StreamDecode(decoder, *is); + plugin->StreamDecode(decoder, *is); - is->Close(); + delete is; } else { - g_printerr("Decoder plugin is not usable\n"); - return 1; + fprintf(stderr, "Decoder plugin is not usable\n"); + return EXIT_FAILURE; } decoder_plugin_deinit_all(); @@ -249,8 +101,8 @@ int main(int argc, char **argv) io_thread_deinit(); if (!decoder.initialized) { - g_printerr("Decoding failed\n"); - return 1; + fprintf(stderr, "Decoding failed\n"); + return EXIT_FAILURE; } return 0; diff --git a/test/run_encoder.cxx b/test/run_encoder.cxx index 838ee708e..f16d8cb0a 100644 --- a/test/run_encoder.cxx +++ b/test/run_encoder.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -18,16 +18,17 @@ */ #include "config.h" -#include "EncoderList.hxx" -#include "EncoderPlugin.hxx" +#include "encoder/EncoderList.hxx" +#include "encoder/EncoderPlugin.hxx" #include "AudioFormat.hxx" #include "AudioParser.hxx" -#include "ConfigData.hxx" +#include "config/ConfigData.hxx" #include "util/Error.hxx" +#include "Log.hxx" #include "stdbin.h" -#include <glib.h> - +#include <stdio.h> +#include <stdlib.h> #include <stddef.h> #include <unistd.h> @@ -50,8 +51,9 @@ int main(int argc, char **argv) /* parse command line */ if (argc > 3) { - g_printerr("Usage: run_encoder [ENCODER] [FORMAT] <IN >OUT\n"); - return 1; + fprintf(stderr, + "Usage: run_encoder [ENCODER] [FORMAT] <IN >OUT\n"); + return EXIT_FAILURE; } if (argc > 1) @@ -63,8 +65,8 @@ int main(int argc, char **argv) const auto plugin = encoder_plugin_get(encoder_name); if (plugin == NULL) { - g_printerr("No such encoder: %s\n", encoder_name); - return 1; + fprintf(stderr, "No such encoder: %s\n", encoder_name); + return EXIT_FAILURE; } config_param param; @@ -73,9 +75,8 @@ int main(int argc, char **argv) Error error; const auto encoder = encoder_init(*plugin, param, error); if (encoder == NULL) { - g_printerr("Failed to initialize encoder: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to initialize encoder"); + return EXIT_FAILURE; } /* open the encoder */ @@ -83,16 +84,14 @@ int main(int argc, char **argv) AudioFormat audio_format(44100, SampleFormat::S16, 2); if (argc > 2) { if (!audio_format_parse(audio_format, argv[2], false, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } } if (!encoder_open(encoder, audio_format, error)) { - g_printerr("Failed to open encoder: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to open encoder"); + return EXIT_FAILURE; } encoder_to_stdout(*encoder); @@ -102,19 +101,20 @@ int main(int argc, char **argv) ssize_t nbytes; while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) { if (!encoder_write(encoder, buffer, nbytes, error)) { - g_printerr("encoder_write() failed: %s\n", - error.GetMessage()); - return 1; + LogError(error, "encoder_write() failed"); + return EXIT_FAILURE; } encoder_to_stdout(*encoder); } if (!encoder_end(encoder, error)) { - g_printerr("encoder_flush() failed: %s\n", - error.GetMessage()); - return 1; + LogError(error, "encoder_flush() failed"); + return EXIT_FAILURE; } encoder_to_stdout(*encoder); + + encoder_close(encoder); + encoder_finish(encoder); } diff --git a/test/run_filter.cxx b/test/run_filter.cxx index 085fc256b..ab99c9a1e 100644 --- a/test/run_filter.cxx +++ b/test/run_filter.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -18,23 +18,29 @@ */ #include "config.h" -#include "ConfigData.hxx" -#include "ConfigGlobal.hxx" +#include "config/ConfigData.hxx" +#include "config/ConfigGlobal.hxx" #include "fs/Path.hxx" #include "AudioParser.hxx" #include "AudioFormat.hxx" -#include "FilterPlugin.hxx" -#include "FilterInternal.hxx" -#include "pcm/PcmVolume.hxx" -#include "MixerControl.hxx" +#include "filter/FilterPlugin.hxx" +#include "filter/FilterInternal.hxx" +#include "pcm/Volume.hxx" +#include "mixer/MixerControl.hxx" #include "stdbin.h" #include "util/Error.hxx" +#include "util/ConstBuffer.hxx" #include "system/FatalError.hxx" +#include "Log.hxx" +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <assert.h> #include <string.h> +#include <stdlib.h> +#include <stdio.h> #include <errno.h> #include <unistd.h> @@ -45,45 +51,20 @@ mixer_set_volume(gcc_unused Mixer *mixer, return true; } -static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - -static const struct config_param * -find_named_config_block(ConfigOption option, const char *name) -{ - const struct config_param *param = NULL; - - while ((param = config_get_next_param(option, param)) != NULL) { - const char *current_name = param->GetBlockValue("name"); - if (current_name != NULL && strcmp(current_name, name) == 0) - return param; - } - - return NULL; -} - static Filter * load_filter(const char *name) { - const struct config_param *param; - - param = find_named_config_block(CONF_AUDIO_FILTER, name); + const config_param *param = + config_find_block(CONF_AUDIO_FILTER, "name", name); if (param == NULL) { - g_printerr("No such configured filter: %s\n", name); + fprintf(stderr, "No such configured filter: %s\n", name); return nullptr; } Error error; Filter *filter = filter_configured_new(*param, error); if (filter == NULL) { - g_printerr("Failed to load filter: %s\n", error.GetMessage()); + LogError(error, "Failed to load filter"); return NULL; } @@ -97,8 +78,8 @@ int main(int argc, char **argv) char buffer[4096]; if (argc < 3 || argc > 4) { - g_printerr("Usage: run_filter CONFIG NAME [FORMAT] <IN\n"); - return 1; + fprintf(stderr, "Usage: run_filter CONFIG NAME [FORMAT] <IN\n"); + return EXIT_FAILURE; } const Path config_path = Path::FromFS(argv[1]); @@ -107,11 +88,11 @@ int main(int argc, char **argv) /* initialize GLib */ +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - - g_log_set_default_handler(my_log_func, NULL); +#endif /* read configuration file (mpd.conf) */ @@ -124,9 +105,8 @@ int main(int argc, char **argv) if (argc > 3) { Error error; if (!audio_format_parse(audio_format, argv[3], false, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } } @@ -134,44 +114,43 @@ int main(int argc, char **argv) Filter *filter = load_filter(argv[2]); if (filter == NULL) - return 1; + return EXIT_FAILURE; /* open the filter */ Error error; const AudioFormat out_audio_format = filter->Open(audio_format, error); if (!out_audio_format.IsDefined()) { - g_printerr("Failed to open filter: %s\n", error.GetMessage()); + LogError(error, "Failed to open filter"); delete filter; - return 1; + return EXIT_FAILURE; } - g_printerr("audio_format=%s\n", - audio_format_to_string(out_audio_format, &af_string)); + fprintf(stderr, "audio_format=%s\n", + audio_format_to_string(out_audio_format, &af_string)); /* play */ while (true) { ssize_t nbytes; - size_t length; - const void *dest; nbytes = read(0, buffer, sizeof(buffer)); if (nbytes <= 0) break; - dest = filter->FilterPCM(buffer, (size_t)nbytes, - &length, error); - if (dest == NULL) { - g_printerr("Filter failed: %s\n", error.GetMessage()); + auto dest = filter->FilterPCM({(const void *)buffer, (size_t)nbytes}, + error); + if (dest.IsNull()) { + LogError(error, "filter/Filter failed"); filter->Close(); delete filter; - return 1; + return EXIT_FAILURE; } - nbytes = write(1, dest, length); + nbytes = write(1, dest.data, dest.size); if (nbytes < 0) { - g_printerr("Failed to write: %s\n", g_strerror(errno)); + fprintf(stderr, "Failed to write: %s\n", + strerror(errno)); filter->Close(); delete filter; return 1; diff --git a/test/run_gunzip.cxx b/test/run_gunzip.cxx new file mode 100644 index 000000000..51bdb532e --- /dev/null +++ b/test/run_gunzip.cxx @@ -0,0 +1,76 @@ +/* + * 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. + */ + +#include "config.h" +#include "fs/io/GunzipReader.hxx" +#include "fs/io/FileReader.hxx" +#include "fs/io/StdioOutputStream.hxx" +#include "util/Error.hxx" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static bool +Copy(OutputStream &dest, Reader &src, Error &error) +{ + while (true) { + char buffer[4096]; + size_t nbytes = src.Read(buffer, sizeof(buffer), error); + if (nbytes == 0) + return !error.IsDefined(); + + if (!dest.Write(buffer, nbytes, error)) + return false; + } +} + +static bool +CopyGunzip(OutputStream &dest, Reader &_src, Error &error) +{ + GunzipReader src(_src, error); + return src.IsDefined() && Copy(dest, src, error); +} + +static bool +CopyGunzip(FILE *_dest, Path src_path, Error &error) +{ + StdioOutputStream dest(_dest); + FileReader src(src_path, error); + return src.IsDefined() && CopyGunzip(dest, src, error); +} + +int +main(int argc, gcc_unused char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: run_gunzip PATH\n"); + return EXIT_FAILURE; + } + + Path path = Path::FromFS(argv[1]); + + Error error; + if (!CopyGunzip(stdout, path, error)) { + fprintf(stderr, "%s\n", error.GetMessage()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/test/run_gzip.cxx b/test/run_gzip.cxx new file mode 100644 index 000000000..c52b32ac7 --- /dev/null +++ b/test/run_gzip.cxx @@ -0,0 +1,79 @@ +/* + * 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. + */ + +#include "config.h" +#include "fs/io/GzipOutputStream.hxx" +#include "fs/io/StdioOutputStream.hxx" +#include "util/Error.hxx" + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +static bool +Copy(OutputStream &dest, int src, Error &error) +{ + while (true) { + char buffer[4096]; + ssize_t nbytes = read(src, buffer, sizeof(buffer)); + if (nbytes <= 0) { + if (nbytes < 0) { + error.SetErrno(); + return false; + } else + return true; + } + + if (!dest.Write(buffer, nbytes, error)) + return false; + } +} + +static bool +CopyGzip(OutputStream &_dest, int src, Error &error) +{ + GzipOutputStream dest(_dest, error); + return dest.IsDefined() && + Copy(dest, src, error) && + dest.Flush(error); +} + +static bool +CopyGzip(FILE *_dest, int src, Error &error) +{ + StdioOutputStream dest(_dest); + return CopyGzip(dest, src, error); +} + +int +main(int argc, gcc_unused char **argv) +{ + if (argc != 1) { + fprintf(stderr, "Usage: run_gzip\n"); + return EXIT_FAILURE; + } + + Error error; + if (!CopyGzip(stdout, STDIN_FILENO, error)) { + fprintf(stderr, "%s\n", error.GetMessage()); + return EXIT_FAILURE; + } + + return EXIT_SUCCESS; +} diff --git a/test/run_inotify.cxx b/test/run_inotify.cxx index c57e6e9ef..df4046356 100644 --- a/test/run_inotify.cxx +++ b/test/run_inotify.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -19,13 +19,11 @@ #include "config.h" #include "ShutdownHandler.hxx" -#include "InotifySource.hxx" +#include "db/update/InotifySource.hxx" #include "event/Loop.hxx" #include "util/Error.hxx" #include "Log.hxx" -#include <glib.h> - #include <sys/inotify.h> static constexpr unsigned IN_MASK = @@ -39,7 +37,7 @@ static void my_inotify_callback(gcc_unused int wd, unsigned mask, const char *name, gcc_unused void *ctx) { - g_print("mask=0x%x name='%s'\n", mask, name); + printf("mask=0x%x name='%s'\n", mask, name); } int main(int argc, char **argv) @@ -47,13 +45,13 @@ int main(int argc, char **argv) const char *path; if (argc != 2) { - g_printerr("Usage: run_inotify PATH\n"); - return 1; + fprintf(stderr, "Usage: run_inotify PATH\n"); + return EXIT_FAILURE; } path = argv[1]; - EventLoop event_loop((EventLoop::Default())); + EventLoop event_loop; const ShutdownHandler shutdown_handler(event_loop); Error error; @@ -62,17 +60,18 @@ int main(int argc, char **argv) nullptr, error); if (source == NULL) { LogError(error); - return 2; + return EXIT_FAILURE; } int descriptor = source->Add(path, IN_MASK, error); if (descriptor < 0) { delete source; LogError(error); - return 2; + return EXIT_FAILURE; } event_loop.Run(); delete source; + return EXIT_SUCCESS; } diff --git a/test/run_input.cxx b/test/run_input.cxx index 3817ed418..1d8cf3a28 100644 --- a/test/run_input.cxx +++ b/test/run_input.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -21,31 +21,34 @@ #include "TagSave.hxx" #include "stdbin.h" #include "tag/Tag.hxx" -#include "ConfigGlobal.hxx" -#include "InputStream.hxx" -#include "InputInit.hxx" +#include "config/ConfigGlobal.hxx" +#include "input/InputStream.hxx" +#include "input/Init.hxx" #include "IOThread.hxx" #include "util/Error.hxx" #include "thread/Cond.hxx" #include "Log.hxx" +#include "fs/io/BufferedOutputStream.hxx" +#include "fs/io/StdioOutputStream.hxx" #ifdef ENABLE_ARCHIVE -#include "ArchiveList.hxx" +#include "archive/ArchiveList.hxx" #endif +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <unistd.h> #include <stdlib.h> static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) +tag_save(FILE *file, const Tag &tag) { - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); + StdioOutputStream sos(file); + BufferedOutputStream bos(sos); + tag_save(bos, tag); + bos.Flush(); } static int @@ -58,27 +61,17 @@ dump_input_stream(InputStream *is) is->Lock(); - /* wait until the stream becomes ready */ - - is->WaitReady(); - - if (!is->Check(error)) { - LogError(error); - is->Unlock(); - return EXIT_FAILURE; - } - /* print meta data */ - if (!is->mime.empty()) - g_printerr("MIME type: %s\n", is->mime.c_str()); + if (is->HasMimeType()) + fprintf(stderr, "MIME type: %s\n", is->GetMimeType()); /* read data and tags from the stream */ while (!is->IsEOF()) { Tag *tag = is->ReadTag(); if (tag != NULL) { - g_printerr("Received a tag:\n"); + fprintf(stderr, "Received a tag:\n"); tag_save(stderr, *tag); delete tag; } @@ -114,17 +107,17 @@ int main(int argc, char **argv) int ret; if (argc != 2) { - g_printerr("Usage: run_input URI\n"); - return 1; + fprintf(stderr, "Usage: run_input URI\n"); + return EXIT_FAILURE; } /* initialize GLib */ +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif - - g_log_set_default_handler(my_log_func, NULL); +#endif /* initialize MPD */ @@ -147,16 +140,16 @@ int main(int argc, char **argv) Mutex mutex; Cond cond; - is = InputStream::Open(argv[1], mutex, cond, error); + is = InputStream::OpenReady(argv[1], mutex, cond, error); if (is != NULL) { ret = dump_input_stream(is); - is->Close(); + delete is; } else { if (error.IsDefined()) LogError(error); else - g_printerr("input_stream::Open() failed\n"); - ret = 2; + fprintf(stderr, "input_stream::Open() failed\n"); + ret = EXIT_FAILURE; } /* deinitialize everything */ diff --git a/test/run_neighbor_explorer.cxx b/test/run_neighbor_explorer.cxx new file mode 100644 index 000000000..c79948d6e --- /dev/null +++ b/test/run_neighbor_explorer.cxx @@ -0,0 +1,85 @@ +/* + * 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. + */ + +#include "config.h" +#include "config/ConfigGlobal.hxx" +#include "neighbor/Listener.hxx" +#include "neighbor/Info.hxx" +#include "neighbor/Glue.hxx" +#include "fs/Path.hxx" +#include "event/Loop.hxx" +#include "util/Error.hxx" +#include "Log.hxx" + +#include <stdio.h> +#include <stdlib.h> + +class MyNeighborListener final : public NeighborListener { + public: + /* virtual methods from class NeighborListener */ + virtual void FoundNeighbor(const NeighborInfo &info) override { + printf("found '%s' (%s)\n", + info.display_name.c_str(), info.uri.c_str()); + } + + virtual void LostNeighbor(const NeighborInfo &info) override { + printf("lost '%s' (%s)\n", + info.display_name.c_str(), info.uri.c_str()); + } +}; + +int +main(int argc, char **argv) +{ + if (argc != 2) { + fprintf(stderr, "Usage: run_neighbor_explorer CONFIG\n"); + return EXIT_FAILURE; + } + + const Path config_path = Path::FromFS(argv[1]); + + /* read configuration file (mpd.conf) */ + + Error error; + + config_global_init(); + if (!ReadConfigFile(config_path, error)) { + LogError(error); + return EXIT_FAILURE; + } + + /* initialize the core */ + + EventLoop loop; + + /* initialize neighbor plugins */ + + MyNeighborListener listener; + NeighborGlue neighbor; + if (!neighbor.Init(loop, listener, error) || !neighbor.Open(error)) { + LogError(error); + return EXIT_FAILURE; + } + + /* run */ + + loop.Run(); + neighbor.Close(); + return EXIT_SUCCESS; +} diff --git a/test/run_normalize.cxx b/test/run_normalize.cxx index 3193fefd2..9a361b790 100644 --- a/test/run_normalize.cxx +++ b/test/run_normalize.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 @@ -30,9 +30,8 @@ #include "util/Error.hxx" #include "stdbin.h" -#include <glib.h> - #include <stddef.h> +#include <stdio.h> #include <unistd.h> #include <string.h> @@ -43,7 +42,7 @@ int main(int argc, char **argv) ssize_t nbytes; if (argc > 2) { - g_printerr("Usage: run_normalize [FORMAT] <IN >OUT\n"); + fprintf(stderr, "Usage: run_normalize [FORMAT] <IN >OUT\n"); return 1; } @@ -51,7 +50,7 @@ int main(int argc, char **argv) if (argc > 1) { Error error; if (!audio_format_parse(audio_format, argv[1], false, error)) { - g_printerr("Failed to parse audio format: %s\n", + fprintf(stderr, "Failed to parse audio format: %s\n", error.GetMessage()); return 1; } diff --git a/test/run_output.cxx b/test/run_output.cxx index 7982bd7de..e6c11669d 100644 --- a/test/run_output.cxx +++ b/test/run_output.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -18,38 +18,33 @@ */ #include "config.h" -#include "OutputControl.hxx" -#include "OutputInternal.hxx" -#include "OutputPlugin.hxx" -#include "ConfigData.hxx" -#include "ConfigGlobal.hxx" -#include "ConfigOption.hxx" +#include "output/Internal.hxx" +#include "output/OutputPlugin.hxx" +#include "config/ConfigData.hxx" +#include "config/ConfigGlobal.hxx" +#include "config/ConfigOption.hxx" #include "Idle.hxx" #include "Main.hxx" #include "event/Loop.hxx" -#include "GlobalEvents.hxx" #include "IOThread.hxx" #include "fs/Path.hxx" #include "AudioParser.hxx" #include "pcm/PcmConvert.hxx" -#include "FilterRegistry.hxx" +#include "filter/FilterRegistry.hxx" #include "PlayerControl.hxx" #include "stdbin.h" #include "util/Error.hxx" +#include "Log.hxx" +#ifdef HAVE_GLIB #include <glib.h> +#endif #include <assert.h> #include <string.h> #include <unistd.h> #include <stdlib.h> - -EventLoop *main_loop; - -void -GlobalEvents::Emit(gcc_unused Event event) -{ -} +#include <stdio.h> const struct filter_plugin * filter_plugin_by_name(gcc_unused const char *name) @@ -58,68 +53,61 @@ filter_plugin_by_name(gcc_unused const char *name) return NULL; } -static const struct config_param * -find_named_config_block(ConfigOption option, const char *name) -{ - const struct config_param *param = NULL; - - while ((param = config_get_next_param(option, param)) != NULL) { - const char *current_name = param->GetBlockValue("name"); - if (current_name != NULL && strcmp(current_name, name) == 0) - return param; - } - - return NULL; -} - -PlayerControl::PlayerControl(gcc_unused unsigned _buffer_chunks, - gcc_unused unsigned _buffered_before_play) {} +PlayerControl::PlayerControl(PlayerListener &_listener, + MultipleOutputs &_outputs, + unsigned _buffer_chunks, + unsigned _buffered_before_play) + :listener(_listener), outputs(_outputs), + buffer_chunks(_buffer_chunks), + buffered_before_play(_buffered_before_play) {} PlayerControl::~PlayerControl() {} -static struct audio_output * -load_audio_output(const char *name) +static AudioOutput * +load_audio_output(EventLoop &event_loop, const char *name) { - const struct config_param *param; - - param = find_named_config_block(CONF_AUDIO_OUTPUT, name); + const config_param *param = + config_find_block(CONF_AUDIO_OUTPUT, "name", name); if (param == NULL) { - g_printerr("No such configured audio output: %s\n", name); + fprintf(stderr, "No such configured audio output: %s\n", name); return nullptr; } - static struct PlayerControl dummy_player_control(32, 4); + static struct PlayerControl dummy_player_control(*(PlayerListener *)nullptr, + *(MultipleOutputs *)nullptr, + 32, 4); Error error; - struct audio_output *ao = - audio_output_new(*param, dummy_player_control, error); + AudioOutput *ao = + audio_output_new(event_loop, *param, + *(MixerListener *)nullptr, + dummy_player_control, + error); if (ao == nullptr) - g_printerr("%s\n", error.GetMessage()); + LogError(error); return ao; } static bool -run_output(struct audio_output *ao, AudioFormat audio_format) +run_output(AudioOutput *ao, AudioFormat audio_format) { /* open the audio output */ Error error; if (!ao_plugin_enable(ao, error)) { - g_printerr("Failed to enable audio output: %s\n", - error.GetMessage()); + LogError(error, "Failed to enable audio output"); return false; } if (!ao_plugin_open(ao, audio_format, error)) { ao_plugin_disable(ao); - g_printerr("Failed to open audio output: %s\n", - error.GetMessage()); + LogError(error, "Failed to open audio output"); return false; } struct audio_format_string af_string; - g_printerr("audio_format=%s\n", - audio_format_to_string(audio_format, &af_string)); + fprintf(stderr, "audio_format=%s\n", + audio_format_to_string(audio_format, &af_string)); size_t frame_size = audio_format.GetFrameSize(); @@ -145,8 +133,7 @@ run_output(struct audio_output *ao, AudioFormat audio_format) if (consumed == 0) { ao_plugin_close(ao); ao_plugin_disable(ao); - g_printerr("Failed to play: %s\n", - error.GetMessage()); + LogError(error, "Failed to play"); return false; } @@ -168,34 +155,36 @@ int main(int argc, char **argv) Error error; if (argc < 3 || argc > 4) { - g_printerr("Usage: run_output CONFIG NAME [FORMAT] <IN\n"); - return 1; + fprintf(stderr, "Usage: run_output CONFIG NAME [FORMAT] <IN\n"); + return EXIT_FAILURE; } const Path config_path = Path::FromFS(argv[1]); AudioFormat audio_format(44100, SampleFormat::S16, 2); +#ifdef HAVE_GLIB #if !GLIB_CHECK_VERSION(2,32,0) g_thread_init(NULL); #endif +#endif /* read configuration file (mpd.conf) */ config_global_init(); if (!ReadConfigFile(config_path, error)) { - g_printerr("%s\n", error.GetMessage()); - return 1; + LogError(error); + return EXIT_FAILURE; } - main_loop = new EventLoop(EventLoop::Default()); + EventLoop event_loop; io_thread_init(); io_thread_start(); /* initialize the audio output */ - struct audio_output *ao = load_audio_output(argv[2]); + AudioOutput *ao = load_audio_output(event_loop, argv[2]); if (ao == NULL) return 1; @@ -203,9 +192,8 @@ int main(int argc, char **argv) if (argc > 3) { if (!audio_format_parse(audio_format, argv[3], false, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } } @@ -219,8 +207,6 @@ int main(int argc, char **argv) io_thread_deinit(); - delete main_loop; - config_global_finish(); return success ? EXIT_SUCCESS : EXIT_FAILURE; diff --git a/test/run_resolver.cxx b/test/run_resolver.cxx index 7da2fd5b2..71cadbeec 100644 --- a/test/run_resolver.cxx +++ b/test/run_resolver.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -22,8 +22,6 @@ #include "util/Error.hxx" #include "Log.hxx" -#include <glib.h> - #ifdef WIN32 #include <ws2tcpip.h> #include <winsock.h> @@ -32,12 +30,13 @@ #include <netdb.h> #endif +#include <stdio.h> #include <stdlib.h> int main(int argc, char **argv) { if (argc != 2) { - g_printerr("Usage: run_resolver HOST\n"); + fprintf(stderr, "Usage: run_resolver HOST\n"); return EXIT_FAILURE; } @@ -51,16 +50,8 @@ int main(int argc, char **argv) } for (const struct addrinfo *i = ai; i != NULL; i = i->ai_next) { - char *p = sockaddr_to_string(i->ai_addr, i->ai_addrlen, - error); - if (p == NULL) { - freeaddrinfo(ai); - LogError(error); - return EXIT_FAILURE; - } - - g_print("%s\n", p); - g_free(p); + const auto s = sockaddr_to_string(i->ai_addr, i->ai_addrlen); + printf("%s\n", s.c_str()); } freeaddrinfo(ai); diff --git a/test/software_volume.cxx b/test/software_volume.cxx index 19a0be88c..1e41f95fd 100644 --- a/test/software_volume.cxx +++ b/test/software_volume.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -24,15 +24,17 @@ */ #include "config.h" -#include "pcm/PcmVolume.hxx" +#include "pcm/Volume.hxx" #include "AudioParser.hxx" #include "AudioFormat.hxx" +#include "util/ConstBuffer.hxx" #include "util/Error.hxx" #include "stdbin.h" +#include "Log.hxx" -#include <glib.h> - +#include <stdio.h> #include <stddef.h> +#include <stdlib.h> #include <unistd.h> int main(int argc, char **argv) @@ -41,28 +43,29 @@ int main(int argc, char **argv) ssize_t nbytes; if (argc > 2) { - g_printerr("Usage: software_volume [FORMAT] <IN >OUT\n"); - return 1; + fprintf(stderr, "Usage: software_volume [FORMAT] <IN >OUT\n"); + return EXIT_FAILURE; } Error error; AudioFormat audio_format(48000, SampleFormat::S16, 2); if (argc > 1) { if (!audio_format_parse(audio_format, argv[1], false, error)) { - g_printerr("Failed to parse audio format: %s\n", - error.GetMessage()); - return 1; + LogError(error, "Failed to parse audio format"); + return EXIT_FAILURE; } } - while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) { - if (!pcm_volume(buffer, nbytes, - audio_format.format, - PCM_VOLUME_1 / 2)) { - g_printerr("pcm_volume() has failed\n"); - return 2; - } + PcmVolume pv; + if (!pv.Open(audio_format.format, error)) { + fprintf(stderr, "%s\n", error.GetMessage()); + return EXIT_FAILURE; + } - gcc_unused ssize_t ignored = write(1, buffer, nbytes); + while ((nbytes = read(0, buffer, sizeof(buffer))) > 0) { + auto dest = pv.Apply({buffer, size_t(nbytes)}); + gcc_unused ssize_t ignored = write(1, dest.data, dest.size); } + + pv.Close(); } diff --git a/test/stdbin.h b/test/stdbin.h index 48cac7338..8b5502e6f 100644 --- a/test/stdbin.h +++ b/test/stdbin.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2011 The Music Player Daemon Project + * 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 diff --git a/test/test_archive.cxx b/test/test_archive.cxx index dbb41fe42..353699574 100644 --- a/test/test_archive.cxx +++ b/test/test_archive.cxx @@ -1,5 +1,5 @@ #include "config.h" -#include "ArchiveLookup.hxx" +#include "archive/ArchiveLookup.hxx" #include "Compiler.h" #include <cppunit/TestFixture.h> diff --git a/test/test_byte_reverse.cxx b/test/test_byte_reverse.cxx index 58673e4f8..0ab97e4d1 100644 --- a/test/test_byte_reverse.cxx +++ b/test/test_byte_reverse.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 diff --git a/test/test_icy_parser.cxx b/test/test_icy_parser.cxx index 2abf60f9e..a996df134 100644 --- a/test/test_icy_parser.cxx +++ b/test/test_icy_parser.cxx @@ -28,7 +28,7 @@ icy_parse_tag(const char *p) static void CompareTagTitle(const Tag &tag, const std::string &title) { - CPPUNIT_ASSERT_EQUAL(1u, tag.num_items); + CPPUNIT_ASSERT_EQUAL(uint16_t(1), tag.num_items); const TagItem &item = *tag.items[0]; CPPUNIT_ASSERT_EQUAL(TAG_TITLE, item.type); @@ -47,7 +47,7 @@ static void TestIcyParserEmpty(const char *input) { Tag *tag = icy_parse_tag(input); - CPPUNIT_ASSERT_EQUAL(0u, tag->num_items); + CPPUNIT_ASSERT_EQUAL(uint16_t(0), tag->num_items); delete tag; } diff --git a/test/test_pcm_all.hxx b/test/test_pcm_all.hxx index 2a0aa8628..7cdd8b63f 100644 --- a/test/test_pcm_all.hxx +++ b/test/test_pcm_all.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -34,8 +34,6 @@ public: void TestDither32(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmDitherTest); - class PcmPackTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PcmPackTest); CPPUNIT_TEST(TestPack24); @@ -47,8 +45,6 @@ public: void TestUnpack24(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmPackTest); - class PcmChannelsTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PcmChannelsTest); CPPUNIT_TEST(TestChannels16); @@ -60,8 +56,6 @@ public: void TestChannels32(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmChannelsTest); - class PcmVolumeTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PcmVolumeTest); CPPUNIT_TEST(TestVolume8); @@ -79,8 +73,6 @@ public: void TestVolumeFloat(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmVolumeTest); - class PcmFormatTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PcmFormatTest); CPPUNIT_TEST(TestFormat8to16); @@ -96,8 +88,6 @@ public: void TestFormatFloat(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmFormatTest); - class PcmMixTest : public CppUnit::TestFixture { CPPUNIT_TEST_SUITE(PcmMixTest); CPPUNIT_TEST(TestMix8); @@ -113,6 +103,19 @@ public: void TestMix32(); }; -CPPUNIT_TEST_SUITE_REGISTRATION(PcmMixTest); +class PcmExportTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(PcmExportTest); + CPPUNIT_TEST(TestShift8); + CPPUNIT_TEST(TestPack24); + CPPUNIT_TEST(TestReverseEndian); + CPPUNIT_TEST(TestDop); + CPPUNIT_TEST_SUITE_END(); + +public: + void TestShift8(); + void TestPack24(); + void TestReverseEndian(); + void TestDop(); +}; #endif diff --git a/test/test_pcm_channels.cxx b/test/test_pcm_channels.cxx index 85c872674..748a76351 100644 --- a/test/test_pcm_channels.cxx +++ b/test/test_pcm_channels.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -22,33 +22,30 @@ #include "test_pcm_util.hxx" #include "pcm/PcmChannels.hxx" #include "pcm/PcmBuffer.hxx" +#include "util/ConstBuffer.hxx" void PcmChannelsTest::TestChannels16() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int16_t, N * 2>(); PcmBuffer buffer; /* stereo to mono */ - size_t dest_size; - const int16_t *dest = - pcm_convert_channels_16(buffer, 1, 2, src, sizeof(src), - &dest_size); - CPPUNIT_ASSERT(dest != NULL); - CPPUNIT_ASSERT_EQUAL(sizeof(src) / 2, dest_size); + auto dest = pcm_convert_channels_16(buffer, 1, 2, { src, N * 2 }); + CPPUNIT_ASSERT(!dest.IsNull()); + CPPUNIT_ASSERT_EQUAL(N, dest.size); for (unsigned i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(int16_t((src[i * 2] + src[i * 2 + 1]) / 2), dest[i]); /* mono to stereo */ - dest = pcm_convert_channels_16(buffer, 2, 1, src, sizeof(src), - &dest_size); - CPPUNIT_ASSERT(dest != NULL); - CPPUNIT_ASSERT_EQUAL(sizeof(src) * 2, dest_size); + dest = pcm_convert_channels_16(buffer, 2, 1, { src, N * 2 }); + CPPUNIT_ASSERT(!dest.IsNull()); + CPPUNIT_ASSERT_EQUAL(N * 4, dest.size); for (unsigned i = 0; i < N; ++i) { CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]); CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]); @@ -58,29 +55,25 @@ PcmChannelsTest::TestChannels16() void PcmChannelsTest::TestChannels32() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int32_t, N * 2>(); PcmBuffer buffer; /* stereo to mono */ - size_t dest_size; - const int32_t *dest = - pcm_convert_channels_32(buffer, 1, 2, src, sizeof(src), - &dest_size); - CPPUNIT_ASSERT(dest != NULL); - CPPUNIT_ASSERT_EQUAL(sizeof(src) / 2, dest_size); + auto dest = pcm_convert_channels_32(buffer, 1, 2, { src, N * 2 }); + CPPUNIT_ASSERT(!dest.IsNull()); + CPPUNIT_ASSERT_EQUAL(N, dest.size); for (unsigned i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(int32_t(((int64_t)src[i * 2] + (int64_t)src[i * 2 + 1]) / 2), dest[i]); /* mono to stereo */ - dest = pcm_convert_channels_32(buffer, 2, 1, src, sizeof(src), - &dest_size); - CPPUNIT_ASSERT(dest != NULL); - CPPUNIT_ASSERT_EQUAL(sizeof(src) * 2, dest_size); + dest = pcm_convert_channels_32(buffer, 2, 1, { src, N * 2 }); + CPPUNIT_ASSERT(!dest.IsNull()); + CPPUNIT_ASSERT_EQUAL(N * 4, dest.size); for (unsigned i = 0; i < N; ++i) { CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2]); CPPUNIT_ASSERT_EQUAL(src[i], dest[i * 2 + 1]); diff --git a/test/test_pcm_dither.cxx b/test/test_pcm_dither.cxx index 710deffcc..09a2b5cf9 100644 --- a/test/test_pcm_dither.cxx +++ b/test/test_pcm_dither.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -19,12 +19,12 @@ #include "test_pcm_all.hxx" #include "test_pcm_util.hxx" -#include "pcm/PcmDither.hxx" +#include "pcm/PcmDither.cxx" void PcmDitherTest::TestDither24() { - constexpr unsigned N = 256; + constexpr unsigned N = 509; const auto src = TestDataBuffer<int32_t, N>(RandomInt24()); int16_t dest[N]; @@ -40,7 +40,7 @@ PcmDitherTest::TestDither24() void PcmDitherTest::TestDither32() { - constexpr unsigned N = 256; + constexpr unsigned N = 509; const auto src = TestDataBuffer<int32_t, N>(); int16_t dest[N]; diff --git a/test/test_pcm_export.cxx b/test/test_pcm_export.cxx new file mode 100644 index 000000000..410e64e4d --- /dev/null +++ b/test/test_pcm_export.cxx @@ -0,0 +1,129 @@ +/* + * 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. + */ + +#include "config.h" +#include "test_pcm_all.hxx" +#include "pcm/PcmExport.hxx" +#include "system/ByteOrder.hxx" +#include "util/ConstBuffer.hxx" + +#include <string.h> + +void +PcmExportTest::TestShift8() +{ + static constexpr int32_t src[] = { 0x0, 0x1, 0x100, 0x10000, 0xffffff }; + static constexpr uint32_t expected[] = { 0x0, 0x100, 0x10000, 0x1000000, 0xffffff00 }; + + PcmExport e; + e.Open(SampleFormat::S24_P32, 2, false, true, false, false); + + auto dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(sizeof(expected), dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0); +} + +void +PcmExportTest::TestPack24() +{ + static constexpr int32_t src[] = { 0x0, 0x1, 0x100, 0x10000, 0xffffff }; + + static constexpr uint8_t expected_be[] = { + 0, 0, 0x0, + 0, 0, 0x1, + 0, 0x1, 0x00, + 0x1, 0x00, 0x00, + 0xff, 0xff, 0xff, + }; + + static constexpr uint8_t expected_le[] = { + 0, 0, 0x0, + 0x1, 0, 0, + 0x00, 0x1, 0, + 0, 0x00, 0x01, + 0xff, 0xff, 0xff, + }; + + static constexpr size_t expected_size = sizeof(expected_be); + static const uint8_t *const expected = IsBigEndian() + ? expected_be : expected_le; + + PcmExport e; + e.Open(SampleFormat::S24_P32, 2, false, false, true, false); + + auto dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(expected_size, dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0); +} + +void +PcmExportTest::TestReverseEndian() +{ + static constexpr uint8_t src[] = { + 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12 + }; + + static constexpr uint8_t expected2[] = { + 2, 1, 4, 3, 6, 5, 8, 7, 10, 9, 12, 11 + }; + + static constexpr uint8_t expected4[] = { + 4, 3, 2, 1, 8, 7, 6, 5, 12, 11, 10, 9, + }; + + PcmExport e; + e.Open(SampleFormat::S8, 2, false, false, false, true); + + auto dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(sizeof(src), dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, src, dest.size) == 0); + + e.Open(SampleFormat::S16, 2, false, false, false, true); + dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(sizeof(expected2), dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, expected2, dest.size) == 0); + + e.Open(SampleFormat::S32, 2, false, false, false, true); + dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(sizeof(expected4), dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, expected4, dest.size) == 0); +} + +void +PcmExportTest::TestDop() +{ + static constexpr uint8_t src[] = { + 0x01, 0x23, 0x45, 0x67, + 0x89, 0xab, 0xcd, 0xef, + }; + + static constexpr uint32_t expected[] = { + 0xff050145, + 0xff052367, + 0xfffa89cd, + 0xfffaabef, + }; + + PcmExport e; + e.Open(SampleFormat::DSD, 2, true, false, false, false); + + auto dest = e.Export({src, sizeof(src)}); + CPPUNIT_ASSERT_EQUAL(sizeof(expected), dest.size); + CPPUNIT_ASSERT(memcmp(dest.data, expected, dest.size) == 0); +} diff --git a/test/test_pcm_format.cxx b/test/test_pcm_format.cxx index 49f4ccd4b..825a8bd84 100644 --- a/test/test_pcm_format.cxx +++ b/test/test_pcm_format.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -29,17 +29,14 @@ void PcmFormatTest::TestFormat8to16() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int8_t, N>(); PcmBuffer buffer; - size_t d_size; PcmDither dither; - auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8, - src, sizeof(src), &d_size); - auto d_end = pcm_end_pointer(d, d_size); - CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d)); + auto d = pcm_convert_to_16(buffer, dither, SampleFormat::S8, src); + CPPUNIT_ASSERT_EQUAL(N, d.size); for (size_t i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 8); @@ -48,16 +45,13 @@ PcmFormatTest::TestFormat8to16() void PcmFormatTest::TestFormat16to24() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int16_t, N>(); PcmBuffer buffer; - size_t d_size; - auto d = pcm_convert_to_24(buffer, SampleFormat::S16, - src, sizeof(src), &d_size); - auto d_end = pcm_end_pointer(d, d_size); - CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d)); + auto d = pcm_convert_to_24(buffer, SampleFormat::S16, src); + CPPUNIT_ASSERT_EQUAL(N, d.size); for (size_t i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 8); @@ -66,16 +60,13 @@ PcmFormatTest::TestFormat16to24() void PcmFormatTest::TestFormat16to32() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int16_t, N>(); PcmBuffer buffer; - size_t d_size; - auto d = pcm_convert_to_32(buffer, SampleFormat::S16, - src, sizeof(src), &d_size); - auto d_end = pcm_end_pointer(d, d_size); - CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d)); + auto d = pcm_convert_to_32(buffer, SampleFormat::S16, src); + CPPUNIT_ASSERT_EQUAL(N, d.size); for (size_t i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(int(src[i]), d[i] >> 16); @@ -84,31 +75,46 @@ PcmFormatTest::TestFormat16to32() void PcmFormatTest::TestFormatFloat() { - constexpr unsigned N = 256; + constexpr size_t N = 509; const auto src = TestDataBuffer<int16_t, N>(); PcmBuffer buffer1, buffer2; - size_t f_size; - auto f = pcm_convert_to_float(buffer1, SampleFormat::S16, - src, sizeof(src), &f_size); - auto f_end = pcm_end_pointer(f, f_size); - CPPUNIT_ASSERT_EQUAL(N, unsigned(f_end - f)); + auto f = pcm_convert_to_float(buffer1, SampleFormat::S16, src); + CPPUNIT_ASSERT_EQUAL(N, f.size); - for (auto i = f; i != f_end; ++i) { - CPPUNIT_ASSERT(*i >= -1.); - CPPUNIT_ASSERT(*i <= 1.); + for (size_t i = 0; i != f.size; ++i) { + CPPUNIT_ASSERT(f[i] >= -1.); + CPPUNIT_ASSERT(f[i] <= 1.); } PcmDither dither; - size_t d_size; auto d = pcm_convert_to_16(buffer2, dither, SampleFormat::FLOAT, - f, f_size, &d_size); - auto d_end = pcm_end_pointer(d, d_size); - CPPUNIT_ASSERT_EQUAL(N, unsigned(d_end - d)); + f.ToVoid()); + CPPUNIT_ASSERT_EQUAL(N, d.size); for (size_t i = 0; i < N; ++i) CPPUNIT_ASSERT_EQUAL(src[i], d[i]); + + /* check if clamping works */ + float *writable = const_cast<float *>(f.data); + *writable++ = 1.01; + *writable++ = 10; + *writable++ = -1.01; + *writable++ = -10; + + d = pcm_convert_to_16(buffer2, dither, + SampleFormat::FLOAT, + f.ToVoid()); + CPPUNIT_ASSERT_EQUAL(N, d.size); + + CPPUNIT_ASSERT_EQUAL(32767, int(d[0])); + CPPUNIT_ASSERT_EQUAL(32767, int(d[1])); + CPPUNIT_ASSERT_EQUAL(-32768, int(d[2])); + CPPUNIT_ASSERT_EQUAL(-32768, int(d[3])); + + for (size_t i = 4; i < N; ++i) + CPPUNIT_ASSERT_EQUAL(src[i], d[i]); } diff --git a/test/test_pcm_main.cxx b/test/test_pcm_main.cxx index c034181d9..0e397a15c 100644 --- a/test/test_pcm_main.cxx +++ b/test/test_pcm_main.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -25,6 +25,14 @@ #include <stdlib.h> +CPPUNIT_TEST_SUITE_REGISTRATION(PcmDitherTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmPackTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmChannelsTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmVolumeTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmFormatTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmMixTest); +CPPUNIT_TEST_SUITE_REGISTRATION(PcmExportTest); + int main(gcc_unused int argc, gcc_unused char **argv) { diff --git a/test/test_pcm_mix.cxx b/test/test_pcm_mix.cxx index 2a8a11388..973b58f4d 100644 --- a/test/test_pcm_mix.cxx +++ b/test/test_pcm_mix.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -21,32 +21,36 @@ #include "test_pcm_all.hxx" #include "test_pcm_util.hxx" #include "pcm/PcmMix.hxx" +#include "pcm/PcmDither.hxx" template<typename T, SampleFormat format, typename G=RandomInt<T>> static void TestPcmMix(G g=G()) { - constexpr unsigned N = 256; + constexpr unsigned N = 509; const auto src1 = TestDataBuffer<T, N>(g); const auto src2 = TestDataBuffer<T, N>(g); + PcmDither dither; + /* portion1=1.0: result must be equal to src1 */ auto result = src1; - bool success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + bool success = pcm_mix(dither, + result.begin(), src2.begin(), sizeof(result), format, 1.0); CPPUNIT_ASSERT(success); - AssertEqualWithTolerance(result, src1, 1); + AssertEqualWithTolerance(result, src1, 3); /* portion1=0.0: result must be equal to src2 */ result = src1; - success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result), format, 0.0); CPPUNIT_ASSERT(success); - AssertEqualWithTolerance(result, src2, 1); + AssertEqualWithTolerance(result, src2, 3); /* portion1=0.5 */ result = src1; - success = pcm_mix(result.begin(), src2.begin(), sizeof(result), + success = pcm_mix(dither, result.begin(), src2.begin(), sizeof(result), format, 0.5); CPPUNIT_ASSERT(success); @@ -54,7 +58,7 @@ TestPcmMix(G g=G()) for (unsigned i = 0; i < N; ++i) expected[i] = (int64_t(src1[i]) + int64_t(src2[i])) / 2; - AssertEqualWithTolerance(result, expected, 1); + AssertEqualWithTolerance(result, expected, 3); } void diff --git a/test/test_pcm_pack.cxx b/test/test_pcm_pack.cxx index cab78c499..fff3e10f0 100644 --- a/test/test_pcm_pack.cxx +++ b/test/test_pcm_pack.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -25,7 +25,7 @@ void PcmPackTest::TestPack24() { - constexpr unsigned N = 256; + constexpr unsigned N = 509; const auto src = TestDataBuffer<int32_t, N>(RandomInt24()); uint8_t dest[N * 3]; @@ -49,7 +49,7 @@ PcmPackTest::TestPack24() void PcmPackTest::TestUnpack24() { - constexpr unsigned N = 256; + constexpr unsigned N = 509; const auto src = TestDataBuffer<uint8_t, N * 3>(); int32_t dest[N]; diff --git a/test/test_pcm_util.hxx b/test/test_pcm_util.hxx index b378c75a7..f1efbc666 100644 --- a/test/test_pcm_util.hxx +++ b/test/test_pcm_util.hxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -17,6 +17,8 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "util/ConstBuffer.hxx" + #include <array> #include <random> @@ -76,6 +78,14 @@ public: operator typename std::array<T, N>::const_pointer() const { return begin(); } + + operator ConstBuffer<T>() const { + return { begin(), size() }; + } + + operator ConstBuffer<void>() const { + return { begin(), size() * sizeof(T) }; + } }; template<typename T> diff --git a/test/test_pcm_volume.cxx b/test/test_pcm_volume.cxx index 764d8b127..2d908f6c1 100644 --- a/test/test_pcm_volume.cxx +++ b/test/test_pcm_volume.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -17,169 +17,109 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include "config.h" #include "test_pcm_all.hxx" -#include "pcm/PcmVolume.hxx" +#include "pcm/Volume.hxx" +#include "pcm/Traits.hxx" +#include "util/ConstBuffer.hxx" +#include "util/Error.hxx" #include "test_pcm_util.hxx" #include <algorithm> #include <string.h> -void -PcmVolumeTest::TestVolume8() +template<SampleFormat F, class Traits=SampleTraits<F>, + typename G=RandomInt<typename Traits::value_type>> +static void +TestVolume(G g=G()) { - constexpr unsigned N = 256; - static int8_t zero[N]; - const auto src = TestDataBuffer<int8_t, N>(); + typedef typename Traits::value_type value_type; + + PcmVolume pv; + CPPUNIT_ASSERT(pv.Open(F, IgnoreError())); - int8_t dest[N]; + constexpr size_t N = 509; + static value_type zero[N]; + const auto _src = TestDataBuffer<value_type, N>(g); + const ConstBuffer<void> src(_src, sizeof(_src)); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S8, 0)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero))); + pv.SetVolume(0); + auto dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, zero, sizeof(zero))); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S8, PCM_VOLUME_1)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src))); + pv.SetVolume(PCM_VOLUME_1); + dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, src.data, src.size)); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S8, PCM_VOLUME_1 / 2)); + pv.SetVolume(PCM_VOLUME_1 / 2); + dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + const auto _dest = ConstBuffer<value_type>::FromVoid(dest); for (unsigned i = 0; i < N; ++i) { - CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2); - CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1); + const auto expected = (_src[i] + 1) / 2; + CPPUNIT_ASSERT(_dest[i] >= expected - 4); + CPPUNIT_ASSERT(_dest[i] <= expected + 4); } + + pv.Close(); } void -PcmVolumeTest::TestVolume16() +PcmVolumeTest::TestVolume8() { - constexpr unsigned N = 256; - static int16_t zero[N]; - const auto src = TestDataBuffer<int16_t, N>(); - - int16_t dest[N]; - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S16, 0)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S16, PCM_VOLUME_1)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S16, PCM_VOLUME_1 / 2)); + TestVolume<SampleFormat::S8>(); +} - for (unsigned i = 0; i < N; ++i) { - CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2); - CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1); - } +void +PcmVolumeTest::TestVolume16() +{ + TestVolume<SampleFormat::S16>(); } void PcmVolumeTest::TestVolume24() { - constexpr unsigned N = 256; - static int32_t zero[N]; - const auto src = TestDataBuffer<int32_t, N>(RandomInt24()); - - int32_t dest[N]; - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S24_P32, 0)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S24_P32, PCM_VOLUME_1)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S24_P32, PCM_VOLUME_1 / 2)); - - for (unsigned i = 0; i < N; ++i) { - CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2); - CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1); - } + TestVolume<SampleFormat::S24_P32>(RandomInt24()); } void PcmVolumeTest::TestVolume32() { - constexpr unsigned N = 256; - static int32_t zero[N]; - const auto src = TestDataBuffer<int32_t, N>(); - - int32_t dest[N]; - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S32, 0)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S32, PCM_VOLUME_1)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src))); - - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::S32, PCM_VOLUME_1 / 2)); - - for (unsigned i = 0; i < N; ++i) { - CPPUNIT_ASSERT(dest[i] >= (src[i] - 1) / 2); - CPPUNIT_ASSERT(dest[i] <= src[i] / 2 + 1); - } + TestVolume<SampleFormat::S32>(); } void PcmVolumeTest::TestVolumeFloat() { - constexpr unsigned N = 256; - static float zero[N]; - const auto src = TestDataBuffer<float, N>(RandomFloat()); + PcmVolume pv; + CPPUNIT_ASSERT(pv.Open(SampleFormat::FLOAT, IgnoreError())); - float dest[N]; + constexpr size_t N = 509; + static float zero[N]; + const auto _src = TestDataBuffer<float, N>(RandomFloat()); + const ConstBuffer<void> src(_src, sizeof(_src)); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::FLOAT, 0)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, zero, sizeof(zero))); + pv.SetVolume(0); + auto dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, zero, sizeof(zero))); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::FLOAT, PCM_VOLUME_1)); - CPPUNIT_ASSERT_EQUAL(0, memcmp(dest, src, sizeof(src))); + pv.SetVolume(PCM_VOLUME_1); + dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + CPPUNIT_ASSERT_EQUAL(0, memcmp(dest.data, src.data, src.size)); - std::copy(src.begin(), src.end(), dest); - CPPUNIT_ASSERT_EQUAL(true, - pcm_volume(dest, sizeof(dest), - SampleFormat::FLOAT, - PCM_VOLUME_1 / 2)); + pv.SetVolume(PCM_VOLUME_1 / 2); + dest = pv.Apply(src); + CPPUNIT_ASSERT_EQUAL(src.size, dest.size); + const auto _dest = ConstBuffer<float>::FromVoid(dest); for (unsigned i = 0; i < N; ++i) - CPPUNIT_ASSERT_DOUBLES_EQUAL(src[i] / 2, dest[i], 1); + CPPUNIT_ASSERT_DOUBLES_EQUAL(_src[i] / 2, _dest[i], 1); + + pv.Close(); } diff --git a/test/test_queue_priority.cxx b/test/test_queue_priority.cxx index fca18fc2d..517cb028c 100644 --- a/test/test_queue_priority.cxx +++ b/test/test_queue_priority.cxx @@ -1,7 +1,6 @@ #include "config.h" -#include "Queue.hxx" -#include "Song.hxx" -#include "Directory.hxx" +#include "queue/Queue.hxx" +#include "DetachedSong.hxx" #include "util/Macros.hxx" #include <cppunit/TestFixture.h> @@ -9,21 +8,8 @@ #include <cppunit/ui/text/TestRunner.h> #include <cppunit/extensions/HelperMacros.h> -Directory detached_root; - -Directory::Directory() {} -Directory::~Directory() {} - -Song * -Song::DupDetached() const -{ - return const_cast<Song *>(this); -} - -void -Song::Free() -{ -} +Tag::Tag(const Tag &) {} +void Tag::Clear() {} static void check_descending_priority(const Queue *queue, @@ -53,12 +39,29 @@ public: void QueuePriorityTest::TestPriority() { - static Song songs[16]; + DetachedSong songs[16] = { + DetachedSong("0.ogg"), + DetachedSong("1.ogg"), + DetachedSong("2.ogg"), + DetachedSong("3.ogg"), + DetachedSong("4.ogg"), + DetachedSong("5.ogg"), + DetachedSong("6.ogg"), + DetachedSong("7.ogg"), + DetachedSong("8.ogg"), + DetachedSong("9.ogg"), + DetachedSong("a.ogg"), + DetachedSong("b.ogg"), + DetachedSong("c.ogg"), + DetachedSong("d.ogg"), + DetachedSong("e.ogg"), + DetachedSong("f.ogg"), + }; Queue queue(32); for (unsigned i = 0; i < ARRAY_SIZE(songs); ++i) - queue.Append(&songs[i], 0); + queue.Append(DetachedSong(songs[i]), 0); CPPUNIT_ASSERT_EQUAL(unsigned(ARRAY_SIZE(songs)), queue.GetLength()); diff --git a/test/test_rewind.cxx b/test/test_rewind.cxx new file mode 100644 index 000000000..3ab37427a --- /dev/null +++ b/test/test_rewind.cxx @@ -0,0 +1,154 @@ +/* + * Unit tests for class RewindInputStream. + */ + +#include "config.h" +#include "input/plugins/RewindInputPlugin.hxx" +#include "input/InputStream.hxx" +#include "thread/Mutex.hxx" +#include "thread/Cond.hxx" +#include "util/Error.hxx" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <string> + +#include <string.h> +#include <stdlib.h> + +class StringInputStream final : public InputStream { + const char *data; + size_t remaining; + +public: + StringInputStream(const char *_uri, + Mutex &_mutex, Cond &_cond, + const char *_data) + :InputStream(_uri, _mutex, _cond), + data(_data), remaining(strlen(data)) { + SetReady(); + } + + /* virtual methods from InputStream */ + bool IsEOF() override { + return remaining == 0; + } + + size_t Read(void *ptr, size_t read_size, + gcc_unused Error &error) override { + size_t nbytes = std::min(remaining, read_size); + memcpy(ptr, data, nbytes); + data += nbytes; + remaining -= nbytes; + offset += nbytes; + return nbytes; + } +}; + +class RewindTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(RewindTest); + CPPUNIT_TEST(TestRewind); + CPPUNIT_TEST_SUITE_END(); + +public: + void TestRewind() { + Mutex mutex; + Cond cond; + + StringInputStream *sis = + new StringInputStream("foo://", mutex, cond, + "foo bar"); + CPPUNIT_ASSERT(sis->IsReady()); + + InputStream *ris = input_rewind_open(sis); + CPPUNIT_ASSERT(ris != sis); + CPPUNIT_ASSERT(ris != nullptr); + + const ScopeLock protect(mutex); + + ris->Update(); + CPPUNIT_ASSERT(ris->IsReady()); + CPPUNIT_ASSERT(!ris->KnownSize()); + CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset()); + + Error error; + char buffer[16]; + size_t nbytes = ris->Read(buffer, 2, error); + CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes); + CPPUNIT_ASSERT_EQUAL('f', buffer[0]); + CPPUNIT_ASSERT_EQUAL('o', buffer[1]); + CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, 2, error); + CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes); + CPPUNIT_ASSERT_EQUAL('o', buffer[0]); + CPPUNIT_ASSERT_EQUAL(' ', buffer[1]); + CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + CPPUNIT_ASSERT(ris->Seek(1, error)); + CPPUNIT_ASSERT_EQUAL(offset_type(1), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, 2, error); + CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes); + CPPUNIT_ASSERT_EQUAL('o', buffer[0]); + CPPUNIT_ASSERT_EQUAL('o', buffer[1]); + CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + CPPUNIT_ASSERT(ris->Seek(0, error)); + CPPUNIT_ASSERT_EQUAL(offset_type(0), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, 2, error); + CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes); + CPPUNIT_ASSERT_EQUAL('f', buffer[0]); + CPPUNIT_ASSERT_EQUAL('o', buffer[1]); + CPPUNIT_ASSERT_EQUAL(offset_type(2), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, sizeof(buffer), error); + CPPUNIT_ASSERT_EQUAL(size_t(2), nbytes); + CPPUNIT_ASSERT_EQUAL('o', buffer[0]); + CPPUNIT_ASSERT_EQUAL(' ', buffer[1]); + CPPUNIT_ASSERT_EQUAL(offset_type(4), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, sizeof(buffer), error); + CPPUNIT_ASSERT_EQUAL(size_t(3), nbytes); + CPPUNIT_ASSERT_EQUAL('b', buffer[0]); + CPPUNIT_ASSERT_EQUAL('a', buffer[1]); + CPPUNIT_ASSERT_EQUAL('r', buffer[2]); + CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset()); + CPPUNIT_ASSERT(ris->IsEOF()); + + CPPUNIT_ASSERT(ris->Seek(3, error)); + CPPUNIT_ASSERT_EQUAL(offset_type(3), ris->GetOffset()); + CPPUNIT_ASSERT(!ris->IsEOF()); + + nbytes = ris->Read(buffer, sizeof(buffer), error); + CPPUNIT_ASSERT_EQUAL(size_t(4), nbytes); + CPPUNIT_ASSERT_EQUAL(' ', buffer[0]); + CPPUNIT_ASSERT_EQUAL('b', buffer[1]); + CPPUNIT_ASSERT_EQUAL('a', buffer[2]); + CPPUNIT_ASSERT_EQUAL('r', buffer[3]); + CPPUNIT_ASSERT_EQUAL(offset_type(7), ris->GetOffset()); + CPPUNIT_ASSERT(ris->IsEOF()); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(RewindTest); + +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; +} diff --git a/test/test_translate_song.cxx b/test/test_translate_song.cxx new file mode 100644 index 000000000..e3c1bcb79 --- /dev/null +++ b/test/test_translate_song.cxx @@ -0,0 +1,318 @@ +/* + * Unit tests for playlist_check_translate_song(). + */ + +#include "config.h" +#include "playlist/PlaylistSong.hxx" +#include "DetachedSong.hxx" +#include "SongLoader.hxx" +#include "client/Client.hxx" +#include "tag/TagBuilder.hxx" +#include "tag/Tag.hxx" +#include "util/Domain.hxx" +#include "fs/AllocatedPath.hxx" +#include "ls.hxx" +#include "Log.hxx" +#include "db/DatabaseSong.hxx" +#include "storage/plugins/LocalStorage.hxx" +#include "util/Error.hxx" +#include "Mapper.hxx" + +#include <cppunit/TestFixture.h> +#include <cppunit/extensions/TestFactoryRegistry.h> +#include <cppunit/ui/text/TestRunner.h> +#include <cppunit/extensions/HelperMacros.h> + +#include <string.h> +#include <stdio.h> + +void +Log(const Domain &domain, gcc_unused LogLevel level, const char *msg) +{ + fprintf(stderr, "[%s] %s\n", domain.GetName(), msg); +} + +bool +uri_supported_scheme(const char *uri) +{ + return memcmp(uri, "http://", 7) == 0; +} + +static const char *const music_directory = "/music"; +static Storage *storage; + +static void +BuildTag(gcc_unused TagBuilder &tag) +{ +} + +template<typename... Args> +static void +BuildTag(TagBuilder &tag, TagType type, const char *value, Args&&... args) +{ + tag.AddItem(type, value); + BuildTag(tag, std::forward<Args>(args)...); +} + +template<typename... Args> +static Tag +MakeTag(Args&&... args) +{ + TagBuilder tag; + BuildTag(tag, std::forward<Args>(args)...); + return tag.Commit(); +} + +static Tag +MakeTag1a() +{ + return MakeTag(TAG_ARTIST, "artist_a1", TAG_TITLE, "title_a1", + TAG_ALBUM, "album_a1"); +} + +static Tag +MakeTag1b() +{ + return MakeTag(TAG_ARTIST, "artist_b1", TAG_TITLE, "title_b1", + TAG_COMMENT, "comment_b1"); +} + +static Tag +MakeTag1c() +{ + return MakeTag(TAG_ARTIST, "artist_b1", TAG_TITLE, "title_b1", + TAG_COMMENT, "comment_b1", TAG_ALBUM, "album_a1"); +} + +static Tag +MakeTag2a() +{ + return MakeTag(TAG_ARTIST, "artist_a2", TAG_TITLE, "title_a2", + TAG_ALBUM, "album_a2"); +} + +static Tag +MakeTag2b() +{ + return MakeTag(TAG_ARTIST, "artist_b2", TAG_TITLE, "title_b2", + TAG_COMMENT, "comment_b2"); +} + +static Tag +MakeTag2c() +{ + return MakeTag(TAG_ARTIST, "artist_b2", TAG_TITLE, "title_b2", + TAG_COMMENT, "comment_b2", TAG_ALBUM, "album_a2"); +} + +static const char *uri1 = "/foo/bar.ogg"; +static const char *uri2 = "foo/bar.ogg"; + +DetachedSong * +DatabaseDetachSong(gcc_unused const Database &db, + gcc_unused const Storage &_storage, + const char *uri, + gcc_unused Error &error) +{ + if (strcmp(uri, uri2) == 0) + return new DetachedSong(uri, MakeTag2a()); + + return nullptr; +} + +bool +DetachedSong::Update() +{ + if (strcmp(GetURI(), uri1) == 0) { + SetTag(MakeTag1a()); + return true; + } + + return false; +} + +const Database * +Client::GetDatabase(gcc_unused Error &error) const +{ + return reinterpret_cast<const Database *>(this); +} + +const Storage * +Client::GetStorage() const +{ + return ::storage; +} + +bool +Client::AllowFile(gcc_unused Path path_fs, gcc_unused Error &error) const +{ + /* always return false, so a SongLoader with a non-nullptr + Client pointer will be regarded "insecure", while one with + client==nullptr will allow all files */ + return false; +} + +static std::string +ToString(const Tag &tag) +{ + std::string result; + + if (!tag.duration.IsNegative()) { + char buffer[64]; + sprintf(buffer, "%d", tag.duration.ToMS()); + result.append(buffer); + } + + for (const auto &item : tag) { + result.push_back('|'); + result.append(tag_item_names[item.type]); + result.push_back('='); + result.append(item.value); + } + + return result; +} + +static std::string +ToString(const DetachedSong &song) +{ + std::string result = song.GetURI(); + result.push_back('|'); + + char buffer[64]; + + if (song.GetLastModified() > 0) { + sprintf(buffer, "%lu", (unsigned long)song.GetLastModified()); + result.append(buffer); + } + + result.push_back('|'); + + if (song.GetStartTime().IsPositive()) { + sprintf(buffer, "%u", song.GetStartTime().ToMS()); + result.append(buffer); + } + + result.push_back('-'); + + if (song.GetEndTime().IsPositive()) { + sprintf(buffer, "%u", song.GetEndTime().ToMS()); + result.append(buffer); + } + + result.push_back('|'); + + result.append(ToString(song.GetTag())); + + return result; +} + +class TranslateSongTest : public CppUnit::TestFixture { + CPPUNIT_TEST_SUITE(TranslateSongTest); + CPPUNIT_TEST(TestAbsoluteURI); + CPPUNIT_TEST(TestInsecure); + CPPUNIT_TEST(TestSecure); + CPPUNIT_TEST(TestInDatabase); + CPPUNIT_TEST(TestRelative); + CPPUNIT_TEST_SUITE_END(); + + void TestAbsoluteURI() { + DetachedSong song1("http://example.com/foo.ogg"); + auto se = ToString(song1); + const SongLoader loader(nullptr, nullptr); + CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored", + loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song1)); + } + + void TestInsecure() { + /* illegal because secure=false */ + DetachedSong song1 (uri1); + const SongLoader loader(*reinterpret_cast<const Client *>(1)); + CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr, + loader)); + } + + void TestSecure() { + DetachedSong song1(uri1, MakeTag1b()); + auto s1 = ToString(song1); + auto se = ToString(DetachedSong(uri1, MakeTag1c())); + + const SongLoader loader(nullptr, nullptr); + CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/ignored", + loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song1)); + } + + void TestInDatabase() { + const SongLoader loader(reinterpret_cast<const Database *>(1), + storage); + + DetachedSong song1("doesntexist"); + CPPUNIT_ASSERT(!playlist_check_translate_song(song1, nullptr, + loader)); + + DetachedSong song2(uri2, MakeTag2b()); + auto s1 = ToString(song2); + auto se = ToString(DetachedSong(uri2, MakeTag2c())); + CPPUNIT_ASSERT(playlist_check_translate_song(song2, nullptr, + loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song2)); + + DetachedSong song3("/music/foo/bar.ogg", MakeTag2b()); + s1 = ToString(song3); + se = ToString(DetachedSong(uri2, MakeTag2c())); + CPPUNIT_ASSERT(playlist_check_translate_song(song3, nullptr, + loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song3)); + } + + void TestRelative() { + const Database &db = *reinterpret_cast<const Database *>(1); + const SongLoader secure_loader(&db, storage); + const SongLoader insecure_loader(*reinterpret_cast<const Client *>(1), + &db, storage); + + /* map to music_directory */ + DetachedSong song1("bar.ogg", MakeTag2b()); + auto s1 = ToString(song1); + auto se = ToString(DetachedSong(uri2, MakeTag2c())); + CPPUNIT_ASSERT(playlist_check_translate_song(song1, "/music/foo", + insecure_loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song1)); + + /* illegal because secure=false */ + DetachedSong song2("bar.ogg", MakeTag2b()); + CPPUNIT_ASSERT(!playlist_check_translate_song(song1, "/foo", + insecure_loader)); + + /* legal because secure=true */ + DetachedSong song3("bar.ogg", MakeTag1b()); + s1 = ToString(song3); + se = ToString(DetachedSong(uri1, MakeTag1c())); + CPPUNIT_ASSERT(playlist_check_translate_song(song3, "/foo", + secure_loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song3)); + + /* relative to http:// */ + DetachedSong song4("bar.ogg", MakeTag2a()); + s1 = ToString(song4); + se = ToString(DetachedSong("http://example.com/foo/bar.ogg", MakeTag2a())); + CPPUNIT_ASSERT(playlist_check_translate_song(song4, "http://example.com/foo", + insecure_loader)); + CPPUNIT_ASSERT_EQUAL(se, ToString(song4)); + } +}; + +CPPUNIT_TEST_SUITE_REGISTRATION(TranslateSongTest); + +int +main(gcc_unused int argc, gcc_unused char **argv) +{ + storage = CreateLocalStorage(Path::FromFS(music_directory)); + + CppUnit::TextUi::TestRunner runner; + auto ®istry = CppUnit::TestFactoryRegistry::getRegistry(); + runner.addTest(registry.makeTest()); + return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/test/test_util.cxx b/test/test_util.cxx index a472391a3..aaadec68f 100644 --- a/test/test_util.cxx +++ b/test/test_util.cxx @@ -4,6 +4,7 @@ #include "config.h" #include "util/UriUtil.hxx" +#include "TestCircularBuffer.hxx" #include <cppunit/TestFixture.h> #include <cppunit/extensions/TestFactoryRegistry.h> @@ -44,10 +45,13 @@ public: uri_remove_auth("http://foo@www.example.com/")); CPPUNIT_ASSERT_EQUAL(std::string(), uri_remove_auth("http://www.example.com/f:oo@bar")); + CPPUNIT_ASSERT_EQUAL(std::string("ftp://ftp.example.com/"), + uri_remove_auth("ftp://foo:bar@ftp.example.com/")); } }; CPPUNIT_TEST_SUITE_REGISTRATION(UriUtilTest); +CPPUNIT_TEST_SUITE_REGISTRATION(TestCircularBuffer); int main(gcc_unused int argc, gcc_unused char **argv) diff --git a/test/test_vorbis_encoder.cxx b/test/test_vorbis_encoder.cxx index 1d95f6deb..59b901da2 100644 --- a/test/test_vorbis_encoder.cxx +++ b/test/test_vorbis_encoder.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -18,12 +18,13 @@ */ #include "config.h" -#include "EncoderList.hxx" -#include "EncoderPlugin.hxx" +#include "encoder/EncoderList.hxx" +#include "encoder/EncoderPlugin.hxx" #include "AudioFormat.hxx" -#include "ConfigData.hxx" +#include "config/ConfigData.hxx" #include "stdbin.h" #include "tag/Tag.hxx" +#include "tag/TagBuilder.hxx" #include "util/Error.hxx" #include <stddef.h> @@ -81,8 +82,13 @@ main(gcc_unused int argc, gcc_unused char **argv) encoder_to_stdout(*encoder); Tag tag; - tag.AddItem(TAG_ARTIST, "Foo"); - tag.AddItem(TAG_TITLE, "Bar"); + + { + TagBuilder tag_builder; + tag_builder.AddItem(TAG_ARTIST, "Foo"); + tag_builder.AddItem(TAG_TITLE, "Bar"); + tag_builder.Commit(tag); + } success = encoder_tag(encoder, &tag, IgnoreError()); assert(success); diff --git a/test/visit_archive.cxx b/test/visit_archive.cxx index 6e66c4696..d4854d8f1 100644 --- a/test/visit_archive.cxx +++ b/test/visit_archive.cxx @@ -1,5 +1,5 @@ /* - * Copyright (C) 2003-2013 The Music Player Daemon Project + * 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 @@ -20,13 +20,13 @@ #include "config.h" #include "stdbin.h" #include "tag/Tag.hxx" -#include "ConfigGlobal.hxx" +#include "config/ConfigGlobal.hxx" #include "IOThread.hxx" -#include "InputInit.hxx" -#include "ArchiveList.hxx" -#include "ArchivePlugin.hxx" -#include "ArchiveFile.hxx" -#include "ArchiveVisitor.hxx" +#include "input/Init.hxx" +#include "archive/ArchiveList.hxx" +#include "archive/ArchivePlugin.hxx" +#include "archive/ArchiveFile.hxx" +#include "archive/ArchiveVisitor.hxx" #include "fs/Path.hxx" #include "util/Error.hxx" @@ -35,16 +35,6 @@ #include <unistd.h> #include <stdlib.h> -static void -my_log_func(const gchar *log_domain, gcc_unused GLogLevelFlags log_level, - const gchar *message, gcc_unused gpointer user_data) -{ - if (log_domain != NULL) - g_printerr("%s: %s\n", log_domain, message); - else - g_printerr("%s\n", message); -} - class MyArchiveVisitor final : public ArchiveVisitor { public: virtual void VisitArchiveEntry(const char *path_utf8) override { @@ -71,8 +61,6 @@ main(int argc, char **argv) g_thread_init(NULL); #endif - g_log_set_default_handler(my_log_func, NULL); - /* initialize MPD */ config_global_init(); @@ -89,7 +77,7 @@ main(int argc, char **argv) /* open the archive and dump it */ - const archive_plugin *plugin = archive_plugin_from_name(plugin_name); + const ArchivePlugin *plugin = archive_plugin_from_name(plugin_name); if (plugin == nullptr) { fprintf(stderr, "No such plugin: %s\n", plugin_name); return EXIT_FAILURE; @@ -97,7 +85,7 @@ main(int argc, char **argv) int result = EXIT_SUCCESS; - ArchiveFile *file = archive_file_open(plugin, path.c_str(), error); + ArchiveFile *file = archive_file_open(plugin, path, error); if (file != nullptr) { MyArchiveVisitor visitor; file->Visit(visitor); |