From ef779aef81d2463f7ace973849b7308b51397b3a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Sun, 13 Jul 2014 01:29:05 +0200
Subject: [PATCH 01/11] configure.ac: check for socket() in libnetwork for
 Haiku

---
 configure.ac | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure.ac b/configure.ac
index dbbb5a5..5ff995f 100644
--- a/configure.ac
+++ b/configure.ac
@@ -198,7 +198,7 @@ AC_SEARCH_LIBS([clock_gettime], [rt])
 AC_SEARCH_LIBS([syslog], [bsd socket inet],
 	[AC_DEFINE(HAVE_SYSLOG, 1, [Define if syslog() is available])])
 
-AC_SEARCH_LIBS([socket], [socket])
+AC_SEARCH_LIBS([socket], [network socket])
 AC_SEARCH_LIBS([gethostbyname], [nsl])
 
 if test x$host_is_linux = xyes; then
-- 
1.8.3.4


From 538cc30e408668dc81299137b3771c5e7999ab81 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Sun, 13 Jul 2014 01:29:39 +0200
Subject: [PATCH 02/11] output: make sure AudioOutput::mixer is initialized

Avoids crashing when libao fails to initialize.
---
 src/output/Init.cxx | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/output/Init.cxx b/src/output/Init.cxx
index eafcec4..79ef4f9 100644
--- a/src/output/Init.cxx
+++ b/src/output/Init.cxx
@@ -48,6 +48,7 @@
 
 AudioOutput::AudioOutput(const AudioOutputPlugin &_plugin)
 	:plugin(_plugin),
+	 mixer(nullptr),
 	 enabled(true), really_enabled(false),
 	 open(false),
 	 pause(false),
-- 
1.8.3.4


From 4ed5e354d778792ed4a0dbc647655865e13de59a Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Mon, 14 Jul 2014 23:10:02 +0200
Subject: [PATCH 03/11] unix: define WCOREDUMP() for platforms that don't
 support it

Haiku does not dump core, it just starts the debugger.
---
 src/unix/Daemon.cxx | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/unix/Daemon.cxx b/src/unix/Daemon.cxx
index 490b2de..49ad394 100644
--- a/src/unix/Daemon.cxx
+++ b/src/unix/Daemon.cxx
@@ -37,6 +37,10 @@
 #include <grp.h>
 #endif
 
+#ifndef WCOREDUMP
+#define WCOREDUMP(v) 0
+#endif
+
 static constexpr Domain daemon_domain("daemon");
 
 #ifndef WIN32
-- 
1.8.3.4


From aabca27705ed851d637b5a16c913f056983ba3ce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Mon, 14 Jul 2014 23:12:03 +0200
Subject: [PATCH 04/11] system/SocketUtil: guard usage of SO_PASSCRED

Haiku has struct ucred but no SO_PASSCRED (yet).
---
 src/system/SocketUtil.cxx | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/system/SocketUtil.cxx b/src/system/SocketUtil.cxx
index b9df0d5..5a88dd1 100644
--- a/src/system/SocketUtil.cxx
+++ b/src/system/SocketUtil.cxx
@@ -75,7 +75,7 @@ socket_bind_listen(int domain, int type, int protocol,
 		return -1;
 	}
 
-#ifdef HAVE_STRUCT_UCRED
+#if defined(HAVE_STRUCT_UCRED) && defined(SO_PASSCRED)
 	setsockopt(fd, SOL_SOCKET, SO_PASSCRED,
 		   (const char *) &reuse, sizeof(reuse));
 #endif
-- 
1.8.3.4


From 7daa8a861af79f0d70db13367dfdec27dfdcd4d6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Mon, 14 Jul 2014 23:16:20 +0200
Subject: [PATCH 05/11] output: add native Haiku audio output and mixer support

Also uses the notification system to display tags.
---
 Makefile.am                              |   8 +
 configure.ac                             |  20 ++
 src/mixer/MixerList.hxx                  |   1 +
 src/mixer/plugins/HaikuMixerPlugin.cxx   |  73 +++++
 src/output/Registry.cxx                  |   4 +
 src/output/plugins/HaikuOutputPlugin.cxx | 453 +++++++++++++++++++++++++++++++
 src/output/plugins/HaikuOutputPlugin.hxx |  34 +++
 7 files changed, 593 insertions(+)
 create mode 100644 src/mixer/plugins/HaikuMixerPlugin.cxx
 create mode 100644 src/output/plugins/HaikuOutputPlugin.cxx
 create mode 100644 src/output/plugins/HaikuOutputPlugin.hxx

diff --git a/Makefile.am b/Makefile.am
index 6e5eb03..7c87573 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1232,6 +1232,14 @@ liboutput_plugins_a_SOURCES += \
 	src/output/plugins/FifoOutputPlugin.hxx
 endif
 
+if HAVE_HAIKU
+liboutput_plugins_a_SOURCES += \
+	src/output/plugins/HaikuOutputPlugin.cxx \
+	src/output/plugins/HaikuOutputPlugin.hxx
+libmixer_plugins_a_SOURCES += \
+	src/mixer/plugins/HaikuMixerPlugin.cxx src/mixer/plugins/HaikuMixerPlugin.hxx
+endif
+
 if ENABLE_PIPE_OUTPUT
 liboutput_plugins_a_SOURCES += \
 	src/output/plugins/PipeOutputPlugin.cxx \
diff --git a/configure.ac b/configure.ac
index 5ff995f..81dec53 100644
--- a/configure.ac
+++ b/configure.ac
@@ -389,6 +389,11 @@ AC_ARG_ENABLE(gme,
 		[enable Blargg's game music emulator plugin]),,
 	enable_gme=auto)
 
+AC_ARG_ENABLE(haiku,
+	AS_HELP_STRING([--enable-haiku],
+		[enable the Haiku output plugin (default: auto)]),,
+	enable_haiku=auto)
+
 AC_ARG_ENABLE(httpd-output,
 	AS_HELP_STRING([--enable-httpd-output],
 		[enables the HTTP server output]),,
@@ -1514,6 +1519,19 @@ fi
 
 AM_CONDITIONAL(HAVE_FIFO, test x$enable_fifo = xyes)
 
+dnl ----------------------------------- Haiku ---------------------------------
+if test x$enable_haiku = xauto; then
+	AC_CHECK_HEADER(media/MediaDefs.h,
+		[enable_haiku=yes],
+		[enable_haiku=no])
+fi
+if test x$enable_haiku = xyes; then
+	AC_DEFINE(HAVE_HAIKU,1,[Define for compiling Haiku support])
+	LIBS="$LIBS -lbe -lmedia"
+fi
+
+AM_CONDITIONAL(HAVE_HAIKU, test x$enable_haiku = xyes)
+
 dnl ------------------------------- HTTPD Output ------------------------------
 if test x$enable_httpd_output = xauto; then
 	# handle HTTPD auto-detection: disable if no encoder is
@@ -1680,6 +1698,7 @@ if
 	test x$enable_roar = xno &&
 	test x$enable_ao = xno &&
 	test x$enable_fifo = xno &&
+	test x$enable_haiku = xno &&
 	test x$enable_httpd_output = xno &&
 	test x$enable_jack = xno &&
 	test x$enable_openal = xno &&
@@ -1854,6 +1873,7 @@ printf '\nPlayback support:\n\t'
 results(alsa,ALSA)
 results(fifo,FIFO)
 results(recorder_output,[File Recorder])
+results(haiku,[Haiku])
 results(httpd_output,[HTTP Daemon])
 results(jack,[JACK])
 printf '\n\t'
diff --git a/src/mixer/MixerList.hxx b/src/mixer/MixerList.hxx
index e75b2e6..8bda104 100644
--- a/src/mixer/MixerList.hxx
+++ b/src/mixer/MixerList.hxx
@@ -29,6 +29,7 @@ struct MixerPlugin;
 
 extern const MixerPlugin software_mixer_plugin;
 extern const MixerPlugin alsa_mixer_plugin;
+extern const MixerPlugin haiku_mixer_plugin;
 extern const MixerPlugin oss_mixer_plugin;
 extern const MixerPlugin roar_mixer_plugin;
 extern const MixerPlugin pulse_mixer_plugin;
diff --git a/src/mixer/plugins/HaikuMixerPlugin.cxx b/src/mixer/plugins/HaikuMixerPlugin.cxx
new file mode 100644
index 0000000..5c9e383
--- /dev/null
+++ b/src/mixer/plugins/HaikuMixerPlugin.cxx
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * Copyright (C) 2010-2011 Philipp 'ph3-der-loewe' Schafft
+ * Copyright (C) 2010-2011 Hans-Kristian 'maister' Arntzen
+ * Copyright (C) 2014 François 'mmu_man' Revol
+ *
+ * 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 "mixer/MixerInternal.hxx"
+#include "output/plugins/HaikuOutputPlugin.hxx"
+#include "Compiler.h"
+
+class HaikuMixer final : public Mixer {
+	/** the base mixer class */
+	HaikuOutput &self;
+
+public:
+	HaikuMixer(HaikuOutput &_output, MixerListener &_listener)
+		:Mixer(haiku_mixer_plugin, _listener),
+		 self(_output) {}
+
+	/* virtual methods from class Mixer */
+	virtual bool Open(gcc_unused Error &error) override {
+		return true;
+	}
+
+	virtual void Close() override {
+	}
+
+	virtual int GetVolume(Error &error) override;
+	virtual bool SetVolume(unsigned volume, Error &error) override;
+};
+
+static Mixer *
+haiku_mixer_init(gcc_unused EventLoop &event_loop, AudioOutput &ao,
+		MixerListener &listener,
+		gcc_unused const config_param &param,
+		gcc_unused Error &error)
+{
+	return new HaikuMixer((HaikuOutput &)ao, listener);
+}
+
+int
+HaikuMixer::GetVolume(gcc_unused Error &error)
+{
+	return haiku_output_get_volume(self);
+}
+
+bool
+HaikuMixer::SetVolume(unsigned volume, gcc_unused Error &error)
+{
+	return haiku_output_set_volume(self, volume);
+}
+
+const MixerPlugin haiku_mixer_plugin = {
+	haiku_mixer_init,
+	false,
+};
diff --git a/src/output/Registry.cxx b/src/output/Registry.cxx
index 566f6b6..4d80ff5 100644
--- a/src/output/Registry.cxx
+++ b/src/output/Registry.cxx
@@ -24,6 +24,7 @@
 #include "plugins/AoOutputPlugin.hxx"
 #include "plugins/FifoOutputPlugin.hxx"
 #include "plugins/httpd/HttpdOutputPlugin.hxx"
+#include "plugins/HaikuOutputPlugin.hxx"
 #include "plugins/JackOutputPlugin.hxx"
 #include "plugins/NullOutputPlugin.hxx"
 #include "plugins/OpenALOutputPlugin.hxx"
@@ -51,6 +52,9 @@ const AudioOutputPlugin *const audio_output_plugins[] = {
 #ifdef HAVE_FIFO
 	&fifo_output_plugin,
 #endif
+#ifdef HAVE_HAIKU
+	&haiku_output_plugin,
+#endif
 #ifdef ENABLE_PIPE_OUTPUT
 	&pipe_output_plugin,
 #endif
diff --git a/src/output/plugins/HaikuOutputPlugin.cxx b/src/output/plugins/HaikuOutputPlugin.cxx
new file mode 100644
index 0000000..fe933cc
--- /dev/null
+++ b/src/output/plugins/HaikuOutputPlugin.cxx
@@ -0,0 +1,453 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ * Copyright (C) 2014 François 'mmu_man' Revol
+ *
+ * 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 "HaikuOutputPlugin.hxx"
+#include "../OutputAPI.hxx"
+#include "mixer/MixerList.hxx"
+#include "util/Error.hxx"
+#include "util/Domain.hxx"
+#include "Log.hxx"
+
+#include <Bitmap.h>
+#include <MediaDefs.h>
+#include <MediaRoster.h>
+#include <Notification.h>
+#include <OS.h>
+#include <StringList.h>
+#include <SoundPlayer.h>
+
+#include <glib.h>
+
+#include <string.h>
+
+#define UTF8_PLAY "\xE2\x96\xB6"
+
+struct HaikuOutput {
+	AudioOutput base;
+
+	size_t write_size;
+
+	media_raw_audio_format* format;
+	BSoundPlayer* sound_player;
+
+	sem_id new_buffer;
+	sem_id buffer_done;
+
+	uint8* buffer;
+	size_t buffer_size;
+	size_t buffer_filled;
+
+	unsigned buffer_delay;
+
+	HaikuOutput()
+		:base(haiku_output_plugin) {}
+
+	bool Initialize(const config_param &param, Error &error) {
+		return base.Configure(param, error);
+	}
+
+	bool Configure(const config_param &param, Error &error);
+};
+
+static constexpr Domain haiku_output_domain("haiku_output");
+
+static void
+haiku_output_error(Error &error_r, status_t err)
+{
+	const char *error = strerror(err);
+	error_r.Set(haiku_output_domain, err, error);
+}
+
+inline bool
+HaikuOutput::Configure(const config_param &param, Error &error)
+{
+	/* XXX: by default we should let the MediaKit propose the buffer size */
+	write_size = param.GetBlockValue("write_size", 4096u);
+
+	format = (media_raw_audio_format*)malloc(
+		sizeof(media_raw_audio_format));
+	if (format == nullptr) {
+		haiku_output_error(error, B_NO_MEMORY);
+		return false;
+	}
+
+	return true;
+}
+
+static bool
+haiku_test_default_device(void)
+{
+	BSoundPlayer testPlayer;
+	return testPlayer.InitCheck() == B_OK;
+
+}
+
+static AudioOutput *
+haiku_output_init(const config_param &param, Error &error)
+{
+	HaikuOutput *ad = new HaikuOutput();
+
+	if (!ad->Initialize(param, error)) {
+		delete ad;
+		return nullptr;
+	}
+
+	if (!ad->Configure(param, error)) {
+		delete ad;
+		return nullptr;
+	}
+
+	return &ad->base;
+}
+
+static void
+haiku_output_finish(AudioOutput *ao)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+
+	free(ad->format);
+	delete_sem(ad->new_buffer);
+	delete_sem(ad->buffer_done);
+	delete ad;
+}
+
+static void
+haiku_output_close(AudioOutput *ao)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+
+	ad->sound_player->SetHasData(false);
+	delete_sem(ad->new_buffer);
+	delete_sem(ad->buffer_done);
+	ad->sound_player->Stop();
+	delete ad->sound_player;
+}
+
+static void
+fill_buffer(void* cookie, void* buffer, size_t size,
+	gcc_unused const media_raw_audio_format& format)
+{
+	HaikuOutput *ad = (HaikuOutput *)cookie;
+
+	ad->buffer = (uint8*)buffer;
+	ad->buffer_size = size;
+	ad->buffer_filled = 0;
+	bigtime_t start = system_time();
+	release_sem(ad->new_buffer);
+	acquire_sem(ad->buffer_done);
+	bigtime_t w = system_time() - start;
+
+	if (w > 5000LL) {
+		FormatDebug(haiku_output_domain,
+			"haiku:fill_buffer waited %Ldus\n", w);
+	}
+
+	if (ad->buffer_filled < ad->buffer_size) {
+		memset(ad->buffer + ad->buffer_filled, 0,
+			ad->buffer_size - ad->buffer_filled);
+		FormatDebug(haiku_output_domain,
+			"haiku:fill_buffer filled %d size %d clearing remainder\n",
+			(int)ad->buffer_filled, (int)ad->buffer_size);
+
+	}
+}
+
+static bool
+haiku_output_open(AudioOutput *ao, AudioFormat &audio_format,
+	       Error &error)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+	status_t err;
+	*(ad->format) = media_multi_audio_format::wildcard;
+
+	switch (audio_format.format) {
+	case SampleFormat::S8:
+		ad->format->format = media_raw_audio_format::B_AUDIO_CHAR;
+		break;
+
+	case SampleFormat::S16:
+		ad->format->format = media_raw_audio_format::B_AUDIO_SHORT;
+		break;
+
+	case SampleFormat::S32:
+		ad->format->format = media_raw_audio_format::B_AUDIO_INT;
+		break;
+
+	case SampleFormat::FLOAT:
+		ad->format->format = media_raw_audio_format::B_AUDIO_FLOAT;
+		break;
+
+	default:
+		/* fall back to float */
+		audio_format.format = SampleFormat::FLOAT;
+		ad->format->format = media_raw_audio_format::B_AUDIO_FLOAT;
+		break;
+	}
+
+	ad->format->frame_rate = audio_format.sample_rate;
+	ad->format->byte_order = B_MEDIA_HOST_ENDIAN;
+	ad->format->channel_count = audio_format.channels;
+
+	ad->buffer_size = 0;
+
+	if (ad->write_size)
+		ad->format->buffer_size = ad->write_size;
+	else
+		ad->format->buffer_size = BMediaRoster::Roster()->AudioBufferSizeFor(
+			ad->format->channel_count, ad->format->format,
+			ad->format->frame_rate, B_UNKNOWN_BUS) * 2;
+
+	FormatDebug(haiku_output_domain,
+		"using haiku driver ad: bs: %d ws: %d "
+		"channels %d rate %f fmt %08lx bs %d\n",
+			(int)ad->buffer_size, (int)ad->write_size,
+			(int)ad->format->channel_count, ad->format->frame_rate,
+			ad->format->format, (int)ad->format->buffer_size);
+
+	ad->sound_player = new BSoundPlayer(ad->format, "MPD Output",
+		fill_buffer, NULL, ad);
+
+	err = ad->sound_player->InitCheck();
+	if (err != B_OK) {
+		delete ad->sound_player;
+		ad->sound_player = NULL;
+		haiku_output_error(error, err);
+		return false;
+	}
+
+	// calculate the allowable delay for the buffer (ms)
+	ad->buffer_delay = ad->format->buffer_size;
+	ad->buffer_delay /= (ad->format->format &
+		media_raw_audio_format::B_AUDIO_SIZE_MASK);
+	ad->buffer_delay /= ad->format->channel_count;
+	ad->buffer_delay *= 1000 / ad->format->frame_rate;
+	// half of the total buffer play time
+	ad->buffer_delay /= 2;
+	FormatDebug(haiku_output_domain,
+		"buffer delay: %d ms\n", ad->buffer_delay);
+
+	ad->new_buffer = create_sem(0, "New buffer request");
+	ad->buffer_done = create_sem(0, "Buffer done");
+
+	ad->sound_player->SetVolume(1.0);
+	ad->sound_player->Start();
+	ad->sound_player->SetHasData(false);
+
+	return true;
+}
+
+static size_t
+haiku_output_play(AudioOutput *ao, const void *chunk, size_t size,
+	       gcc_unused Error &error)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+	BSoundPlayer* const soundPlayer = ad->sound_player;
+	const uint8 *buffer = (const uint8 *)chunk;
+
+	if (size == 0) {
+		soundPlayer->SetHasData(false);
+		return 0;
+	}
+
+	if (!soundPlayer->HasData())
+		soundPlayer->SetHasData(true);
+	acquire_sem(ad->new_buffer);
+
+	size_t bytesLeft = size;
+	while (bytesLeft > 0) {
+		if (ad->buffer_filled == ad->buffer_size) {
+			// Request another buffer from BSoundPlayer
+			release_sem(ad->buffer_done);
+			acquire_sem(ad->new_buffer);
+		}
+
+		const size_t copyBytes = std::min(bytesLeft, ad->buffer_size
+			- ad->buffer_filled);
+		memcpy(ad->buffer + ad->buffer_filled, buffer,
+			copyBytes);
+		ad->buffer_filled += copyBytes;
+		buffer += copyBytes;
+		bytesLeft -= copyBytes;
+	}
+
+
+	if (ad->buffer_filled < ad->buffer_size) {
+		// Continue filling this buffer the next time this function is called
+		release_sem(ad->new_buffer);
+	} else {
+		// Buffer is full
+		release_sem(ad->buffer_done);
+		//soundPlayer->SetHasData(false);
+	}
+
+	return size;
+}
+
+static unsigned
+haiku_output_delay(AudioOutput *ao)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+
+	unsigned delay = ad->buffer_filled ? 0 : ad->buffer_delay;
+
+	//FormatDebug(haiku_output_domain,
+	//		"delay=%d\n", delay / 2);
+	// XXX: doesn't work
+	//return (delay / 2) ? 1 : 0;
+	(void)delay;
+
+	return 0;
+}
+
+static void
+haiku_send_tag(AudioOutput *ao, const Tag *meta)
+{
+	HaikuOutput *ad = (HaikuOutput *)ao;
+	const Tag &tag = *meta;
+
+	BNotification notification(B_INFORMATION_NOTIFICATION);
+
+	BString messageId("mpd_");
+	messageId << find_thread(NULL);
+	notification.SetMessageID(messageId);
+
+	notification.SetGroup("Music Player Daemon");
+
+	char timebuf[16];
+	snprintf(timebuf, sizeof(timebuf), "%02d:%02d:%02d",
+		 tag.time / 3600, (tag.time % 3600) / 60, tag.time % 60);
+
+	BString artist;
+	BString album;
+	BString title;
+	BString track;
+	BString name;
+
+	for (unsigned i = 0; i < tag.num_items; i++)
+	{
+		switch (tag.items[i]->type) {
+		case TAG_ARTIST:
+		case TAG_ALBUM_ARTIST:
+			if (artist.Length() == 0)
+				artist << tag.items[i]->value;
+			break;
+		case TAG_ALBUM:
+			if (album.Length() == 0)
+				album << tag.items[i]->value;
+			break;
+		case TAG_TITLE:
+			if (title.Length() == 0)
+				title << tag.items[i]->value;
+			break;
+		case TAG_TRACK:
+			if (track.Length() == 0)
+				track << tag.items[i]->value;
+			break;
+		case TAG_NAME:
+			if (name.Length() == 0)
+				name << tag.items[i]->value;
+			break;
+		case TAG_GENRE:
+		case TAG_DATE:
+		case TAG_PERFORMER:
+		case TAG_COMMENT:
+		case TAG_DISC:
+		case TAG_COMPOSER:
+		case TAG_MUSICBRAINZ_ARTISTID:
+		case TAG_MUSICBRAINZ_ALBUMID:
+		case TAG_MUSICBRAINZ_ALBUMARTISTID:
+		case TAG_MUSICBRAINZ_TRACKID:
+		default:
+			FormatDebug(haiku_output_domain,
+				"tag.items[%d]: type %d value '%s'\n",
+				i, tag.items[i]->type, tag.items[i]->value);
+			break;
+		}
+	}
+
+	notification.SetTitle(UTF8_PLAY " Now Playing:");
+
+	BStringList content;
+	if (name.Length())
+		content.Add(name);
+	if (artist.Length())
+		content.Add(artist);
+	if (album.Length())
+		content.Add(album);
+	if (track.Length())
+		content.Add(track);
+	if (title.Length())
+		content.Add(title);
+
+	if (content.CountStrings() == 0)
+		content.Add("(Unknown)");
+
+	BString full = content.Join(" " B_UTF8_BULLET " ");
+
+	if (tag.time > 0)
+		full << " (" << timebuf << ")";
+
+	notification.SetContent(full);
+
+	notification.Send();
+}
+
+int
+haiku_output_get_volume(HaikuOutput &haiku)
+{
+	BSoundPlayer* const soundPlayer = haiku.sound_player;
+
+	if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
+		return 0;
+
+	return (int)(soundPlayer->Volume() * 100 + 0.5);
+}
+
+bool
+haiku_output_set_volume(HaikuOutput &haiku, unsigned volume)
+{
+	BSoundPlayer* const soundPlayer = haiku.sound_player;
+
+	if (soundPlayer == NULL || soundPlayer->InitCheck() != B_OK)
+		return false;
+
+	soundPlayer->SetVolume((float)volume / 100);
+	return true;
+}
+
+const struct AudioOutputPlugin haiku_output_plugin = {
+	"haiku",
+	haiku_test_default_device,
+	haiku_output_init,
+	haiku_output_finish,
+	nullptr,
+	nullptr,
+	haiku_output_open,
+	haiku_output_close,
+	haiku_output_delay,
+	haiku_send_tag,
+	haiku_output_play,
+	nullptr,
+	nullptr,
+	nullptr,
+
+	&haiku_mixer_plugin,
+};
diff --git a/src/output/plugins/HaikuOutputPlugin.hxx b/src/output/plugins/HaikuOutputPlugin.hxx
new file mode 100644
index 0000000..f3f224d
--- /dev/null
+++ b/src/output/plugins/HaikuOutputPlugin.hxx
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2003-2014 The Music Player Daemon Project
+ * http://www.musicpd.org
+ * Copyright (C) 2014 François 'mmu_man' Revol
+ *
+ * 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 MPD_HAIKU_OUTPUT_PLUGIN_HXX
+#define MPD_HAIKU_OUTPUT_PLUGIN_HXX
+
+class HaikuOutput;
+
+extern const struct AudioOutputPlugin haiku_output_plugin;
+
+int
+haiku_output_get_volume(HaikuOutput &haiku);
+
+bool
+haiku_output_set_volume(HaikuOutput &haiku, unsigned volume);
+
+#endif
-- 
1.8.3.4


From e91b2b7299d4f337549713ec9ef3a347d280a8ee Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Thu, 31 Jul 2014 23:03:07 +0200
Subject: [PATCH 06/11] Haiku: add an HVIF icon

3D version reinterpreted from the official 2D design,
reusing existing Haiku icons.

Icon-O-Matic source file.
Same as data/artwork/icons/App_MusicPD in the Haiku tree as hrev47609.
---
 src/haiku/App_MusicPD | Bin 0 -> 46028 bytes
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 src/haiku/App_MusicPD

diff --git a/src/haiku/App_MusicPD b/src/haiku/App_MusicPD
new file mode 100644
index 0000000000000000000000000000000000000000..4d341fdbfd0325647a657bf8849496b2dc33ecf8
GIT binary patch
literal 46028
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

literal 0
HcmV?d00001

-- 
1.8.3.4


From 255425c7fe9cc6ce6ae5e1cf7ec30ff637549723 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Thu, 31 Jul 2014 23:09:29 +0200
Subject: [PATCH 07/11] Haiku: add icon as resource definition file

---
 src/haiku/mpd.rdef | 64 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 64 insertions(+)
 create mode 100644 src/haiku/mpd.rdef

diff --git a/src/haiku/mpd.rdef b/src/haiku/mpd.rdef
new file mode 100644
index 0000000..30fcfe4
--- /dev/null
+++ b/src/haiku/mpd.rdef
@@ -0,0 +1,64 @@
+
+resource vector_icon {
+	$"6E6369661F050102031604BEE29BBEC5403EC540BEE29B4A10004A10000001C6"
+	$"70D073FFFF020116033EB0000000000000003EB000482000482000BE4B0084FF"
+	$"32020316023CAF103CF749BCF7493CAF104A07A44A1DB7A143FFFF02031602BC"
+	$"AB8FBCFA713CFA71BCAB8F4A05E34A004BAB08FFFF03010000020016023CC7EE"
+	$"389BC0BA16573E39B04977C842ADC700FFFFD3020006023C529D3753A2B8966F"
+	$"3D9D084B6044496AAF00474747FFA5A0A002001602BC4E76BC411B3C90DABCA0"
+	$"0D47587D4ABA850090FFD40200160238313C3B5CF0BFCD963C7AAC4C13943FCA"
+	$"F901ECFFC3054B04017E020106023E1C1538010FB7C32B3DF5E649B8BE48DD4A"
+	$"000593DCFF00337F020006023879063B8224BE2CC83B10DB4A1F6F49B894FF9A"
+	$"9A9A00242222020006033C69A60000000000003E186148800049800058F3F3F3"
+	$"00D4CECEFFD9D9D9038DFF06050002001602B2E4F7386B91BA78F7B4F4FD49FB"
+	$"A94AE12500CEFF6603010000020006023C55B638309FBA16573E39B049E9FF43"
+	$"840A008B8787FF161515020016023C57B5364381B785863DA4F54B27C349B7BB"
+	$"0010FF4C02001602BC4E76BC411B3C90DABCA00D47587D4ABA850060FF500200"
+	$"160238313C3B5CF0BFCD963C7AAC4C13943FCAF90174FF22055C04017E020016"
+	$"023879063B8224BE2CC83B10DB4A1F6F49B894FF59001E020016033C3DA60000"
+	$"000000003E186148AC0049800058AD0076FA800333C805020106023A40000000"
+	$"000000003980004A300048400000767676FC403E3E020106023E1C1538010FB7"
+	$"C32B3DF5E649B8BE48DD4A000593DCFF00337F05002102044022C65922B92622"
+	$"224022B92622C659405EB9265EC6595E5E405EC6595EB9260A062E262E4B4C5A"
+	$"5650562C38220A064C5C545C604FCA1BC4875C4A58480A042E264C32562C3822"
+	$"0A044C324C5A5650562C0A042E262E4B4C5A4C320A044934494E3043302A0A04"
+	$"BA29C0283043302ABA31B7540A04494B494E304332C0270A044934494B3241BA"
+	$"31B7540A043E25432252264D2A08043E2543225226522C0A034D2A5226522C08"
+	$"02464F47C5ED0A043246324A4453444E0A04344834494250424E08025436503A"
+	$"0A06262E264C485E5252523430280A04262E483C523430280A04483C485E5252"
+	$"52340A04262E264C485E483C0A04443D4456284928320A04B6F9C28C28492832"
+	$"B701BA840A044454445728492AC28B0A04443D44542A47B701BA840A04382B3D"
+	$"284E2D49310804382B3D284E2D4E330A0349304E2C4E320802425843C9830A06"
+	$"486054606052CA1BC5B95C4D524802044530C2D730C0A430403540BAB540BC06"
+	$"4538C0A438C2D7384A354ABC064ABAB50803452145335B250A044934494B3241"
+	$"BA31B754240A0B0102023EF45B0000000000003EF45B487749B685270A05010B"
+	$"1A3EF45B0000000000003EF45B487749B6852715FF01178400040A09010A0A3E"
+	$"F45B0000000000003EF45B487749B6852715FF0A0A010C023EF45B0000000000"
+	$"003EF45B487749B685270A050101123EF45B0000000000003EF45B487749B685"
+	$"2701178400040A060103023EF45B0000000000003EF45B487749B685270A0701"
+	$"04023EF45B0000000000003EF45B487749B685270A08020506023EF45B000000"
+	$"0000003EF45B487749B685270A0C0109023EF45B0000000000003EF45B487749"
+	$"B685270A0D01070A3EF45B0000000000003EF45B487749B6852715FF0A0E0108"
+	$"0A3EF45B0000000000003EF45B487749B6852715FF0A0F010D1A3EF45B000000"
+	$"0000003EF45B487749B6852715FF01178220040A0A010E0A3EF45B0000000000"
+	$"003EF45B487749B6852715FF0A11010F0A3EF45B0000000000003EF45B487749"
+	$"B6852715FF0A0B01000A3D43F93C2B26BD304E3DF9DE48FCA544AB2E15FF0A00"
+	$"0100123CF8FE3C832FBCE7163E4DA3480D86C5C7B501178400040A010100023C"
+	$"F8FE3C832FBCE7163E4DA3480D86C5C7B50A020100023AC6433A584EBAB58C3C"
+	$"265448124D45D0400A0301001A3CB1A73C46E3BCA16C3E165C480E5DC4720015"
+	$"FF01178200040A0401001A3C808E3C1D64BC71B33DE0FC480EF2C30DBC15FF01"
+	$"178200040A18011D023EAAAA0000000000003EAAAA47155548B0480A12011A1A"
+	$"3EAAAA0000000000003EAAAA47155548B04815FF01178400040A1601190A3EAA"
+	$"AA0000000000003EAAAA47155548B04815FF0A17011B0A3EAAAA000000000000"
+	$"3EAAAA47155548B04815FF0A120111123EAAAA0000000000003EAAAA47155548"
+	$"B04801178400040A130112023EAAAA0000000000003EAAAA47155548B0480A14"
+	$"0113023EAAAA0000000000003EAAAA47155548B0480A15021415023EAAAA0000"
+	$"000000003EAAAA47155548B0480A1D01180A3EAAAA0000000000003EAAAA4715"
+	$"5548B04815FF0A1D01180A3EAAAA0000000000003EAAAA47155548B04800150A"
+	$"1901160A3EAAAA0000000000003EAAAA47155548B04815FF0A1A01170A3EAAAA"
+	$"0000000000003EAAAA47155548B04815FF0A1B011C1A3EAAAA0000000000003E"
+	$"AAAA47155548B04815FF01178220040A1C011E023EAAAA0000000000003EAAAA"
+	$"47155548B0480A12011F1A3EAAAA0000000000003EAAAA47155548B04815FF01"
+	$"178222040A12011F1A3EAAAA0000000000003EAAAA47155548B0480015011784"
+	$"2204"
+};
-- 
1.8.3.4


From aa6e9cc1fbe13da18685efb28122462b55c57fa9 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Thu, 31 Jul 2014 23:12:56 +0200
Subject: [PATCH 08/11] Haiku: add resources: application signature and flags

Since we do not handle B_QUIT_REQUESTED because the BApplication
does not Run(), use the background flag to avoid showing up in Deskbar.
---
 src/haiku/mpd.rdef | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/haiku/mpd.rdef b/src/haiku/mpd.rdef
index 30fcfe4..6f1aca2 100644
--- a/src/haiku/mpd.rdef
+++ b/src/haiku/mpd.rdef
@@ -1,3 +1,8 @@
+resource app_signature "application/x-vnd.MusicPD";
+
+resource app_flags B_BACKGROUND_APP;
+
+// TODO: resource app_version {};
 
 resource vector_icon {
 	$"6E6369661F050102031604BEE29BBEC5403EC540BEE29B4A10004A10000001C6"
-- 
1.8.3.4


From 913cc76583cd70d3cf6b0d12ba716699039180de Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Fri, 1 Aug 2014 19:03:32 +0200
Subject: [PATCH 09/11] configure: add tests for Haiku tools (rc, xres)

---
 configure.ac | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/configure.ac b/configure.ac
index 81dec53..83b5ecf 100644
--- a/configure.ac
+++ b/configure.ac
@@ -114,6 +114,10 @@ darwin*)
 solaris*)
 	host_is_solaris=yes
 	;;
+haiku*)
+	AC_CHECK_TOOL(RC, rc)
+	AC_CHECK_TOOL(XRES, xres)
+	;;
 esac
 
 AM_CONDITIONAL([ANDROID], [test x$host_is_android = xyes])
-- 
1.8.3.4


From e8dfa37617e7c83798ecf2e548ce3dff444df7b7 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Fri, 1 Aug 2014 19:03:54 +0200
Subject: [PATCH 10/11] Makefile.am: add the Haiku resources to the mpd binary

---
 Makefile.am | 25 ++++++++++++++++++++++++-
 1 file changed, 24 insertions(+), 1 deletion(-)

diff --git a/Makefile.am b/Makefile.am
index 7c87573..fefc746 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -333,6 +333,28 @@ src_mpd_DEPENDENCIES = src/win32/mpd_win32_rc.$(OBJEXT)
 src_mpd_LDFLAGS = -Wl,src/win32/mpd_win32_rc.$(OBJEXT)
 endif
 
+#
+# Haiku resource file
+#
+
+src/haiku/mpd.rsrc: src/haiku/mpd.rdef
+	$(RC) -o $@ $<
+
+if HAVE_HAIKU
+noinst_DATA = src/haiku/mpd.rdef
+
+EXTRA_src_mpd_DEPENDENCIES = src/haiku/mpd.rsrc
+
+src/mpd.haiku-rsrc-done: src/mpd src/haiku/mpd.rsrc
+	$(XRES) -o src/mpd src/haiku/mpd.rsrc
+	@touch src/mpd.haiku-rsrc-done
+
+all-local: src/mpd.haiku-rsrc-done
+
+clean-local:
+	rm -rf src/haiku/mpd.rsrc src/mpd.haiku-rsrc-done
+endif
+
 if ENABLE_DATABASE
 if ENABLE_INOTIFY
 libmpd_a_SOURCES += \
@@ -2079,4 +2101,5 @@ EXTRA_DIST = $(doc_DATA) autogen.sh \
 	test/test_archive_zzip.sh \
 	$(wildcard scripts/*.sh) \
 	$(man_MANS) $(DOCBOOK_FILES) doc/mpdconf.example doc/doxygen.conf \
-	src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico
+	src/win32/mpd_win32_rc.rc.in src/win32/mpd.ico \
+	src/haiku/App_MusicPD
-- 
1.8.3.4


From fd01e80a754f8c180fc5638df509502fa6a80768 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Thu, 31 Jul 2014 23:18:06 +0200
Subject: [PATCH 11/11] output/haiku: use the icon for notifications

---
 src/output/plugins/HaikuOutputPlugin.cxx | 53 +++++++++++++++++++++++++++++++-
 1 file changed, 52 insertions(+), 1 deletion(-)

diff --git a/src/output/plugins/HaikuOutputPlugin.cxx b/src/output/plugins/HaikuOutputPlugin.cxx
index fe933cc..0f111c6 100644
--- a/src/output/plugins/HaikuOutputPlugin.cxx
+++ b/src/output/plugins/HaikuOutputPlugin.cxx
@@ -26,11 +26,15 @@
 #include "util/Domain.hxx"
 #include "Log.hxx"
 
+#include <AppFileInfo.h>
+#include <Application.h>
 #include <Bitmap.h>
+#include <IconUtils.h>
 #include <MediaDefs.h>
 #include <MediaRoster.h>
 #include <Notification.h>
 #include <OS.h>
+#include <Resources.h>
 #include <StringList.h>
 #include <SoundPlayer.h>
 
@@ -76,6 +80,27 @@ haiku_output_error(Error &error_r, status_t err)
 	error_r.Set(haiku_output_domain, err, error);
 }
 
+static void
+initialize_application()
+{
+	// required to send the notification with a bitmap
+	// TODO: actually Run() it and handle B_QUIT_REQUESTED
+	// TODO: use some locking?
+	if (be_app == NULL) {
+		FormatDebug(haiku_output_domain, "creating be_app\n");
+		new BApplication("application/x-vnd.MusicPD");
+	}
+}
+
+static void
+finalize_application()
+{
+	// TODO: use some locking?
+	delete be_app;
+	be_app = NULL;
+	FormatDebug(haiku_output_domain, "deleting be_app\n");
+}
+
 inline bool
 HaikuOutput::Configure(const config_param &param, Error &error)
 {
@@ -103,6 +128,8 @@ haiku_test_default_device(void)
 static AudioOutput *
 haiku_output_init(const config_param &param, Error &error)
 {
+	initialize_application();
+
 	HaikuOutput *ad = new HaikuOutput();
 
 	if (!ad->Initialize(param, error)) {
@@ -127,6 +154,8 @@ haiku_output_finish(AudioOutput *ao)
 	delete_sem(ad->new_buffer);
 	delete_sem(ad->buffer_done);
 	delete ad;
+
+	finalize_application();
 }
 
 static void
@@ -320,8 +349,28 @@ haiku_output_delay(AudioOutput *ao)
 static void
 haiku_send_tag(AudioOutput *ao, const Tag *meta)
 {
-	HaikuOutput *ad = (HaikuOutput *)ao;
+	//HaikuOutput *ad = (HaikuOutput *)ao;
+	(void)ao;
 	const Tag &tag = *meta;
+	status_t err;
+
+	/* lazily initialized */
+	static BBitmap *icon = NULL;
+
+	if (icon == NULL) {
+		BAppFileInfo info;
+		BResources resources;
+		err = resources.SetToImage((const void *)&haiku_send_tag);
+		BFile file(resources.File());
+		err = info.SetTo(&file);
+		icon = new BBitmap(BRect(0, 0, (float)B_LARGE_ICON - 1,
+			(float)B_LARGE_ICON - 1), B_BITMAP_NO_SERVER_LINK, B_RGBA32);
+		err = info.GetIcon(icon, B_LARGE_ICON);
+		if (err != B_OK) {
+			delete icon;
+			icon = NULL;
+		}
+	}
 
 	BNotification notification(B_INFORMATION_NOTIFICATION);
 
@@ -407,6 +456,8 @@ haiku_send_tag(AudioOutput *ao, const Tag *meta)
 
 	notification.SetContent(full);
 
+	err = notification.SetIcon(icon);
+
 	notification.Send();
 }
 
-- 
1.8.3.4

From af2b547614d4813d2e24e4b70bfd30ea00e0800c Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Fri, 15 Aug 2014 21:12:50 +0200
Subject: [PATCH 1/2] util: Fix header for strcasecmp

According to POSIX and both OSX and Linux manpages,
strcasecmp comes from strings.h, not string.h.

Most OSes also have them available in string.h,
but we just fixed the headers on Haiku and it now
only provides them in strings.h.

We might want to fall back to string.h for other
OSes though...

cf.
http://pubs.opengroup.org/onlinepubs/009695399/functions/strcasecmp.html
http://linux.die.net/man/3/strcasecmp
https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/strcasecmp.3.html
---
 src/util/ASCII.hxx | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/util/ASCII.hxx b/src/util/ASCII.hxx
index adea6dc..4a65254 100644
--- a/src/util/ASCII.hxx
+++ b/src/util/ASCII.hxx
@@ -30,10 +30,13 @@
 #ifndef MPD_ASCII_HXX
 #define MPD_ASCII_HXX
 
+#include "config.h"
 #include "Compiler.h"
 
 #include <assert.h>
-#include <string.h>
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
 
 /**
  * Determine whether two strings are equal, ignoring case for ASCII
-- 
2.1.0.rc1


From c761b00e3a1f2b92b15b54a9a9626b123164e174 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Fran=C3=A7ois=20Revol?= <revol@free.fr>
Date: Fri, 15 Aug 2014 22:17:45 +0200
Subject: [PATCH 2/2] icu: include strings.h for strcasecmp

Again, POSIX says strcasecmp is not in string.h.
---
 src/lib/icu/Collate.cxx | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/lib/icu/Collate.cxx b/src/lib/icu/Collate.cxx
index f6621eb..7542c0e 100644
--- a/src/lib/icu/Collate.cxx
+++ b/src/lib/icu/Collate.cxx
@@ -38,6 +38,9 @@
 
 #include <assert.h>
 #include <string.h>
+#if HAVE_STRINGS_H
+#include <strings.h>
+#endif
 
 #ifdef HAVE_ICU
 static UCollator *collator;
-- 
2.1.0.rc1

