From 0debba0f6e35d88ad17734fda2605e4f97f19820 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Tue, 2 Dec 2014 18:16:33 +0100
Subject: [PATCH] mixer/null: new mixer plugin

---
 Makefile.am                           |  1 +
 NEWS                                  |  2 +
 doc/user.xml                          |  6 ++-
 src/mixer/MixerList.hxx               |  1 +
 src/mixer/MixerType.cxx               |  2 +
 src/mixer/MixerType.hxx               |  3 ++
 src/mixer/plugins/NullMixerPlugin.cxx | 67 +++++++++++++++++++++++++++
 src/output/Init.cxx                   |  4 ++
 8 files changed, 84 insertions(+), 2 deletions(-)
 create mode 100644 src/mixer/plugins/NullMixerPlugin.cxx

diff --git a/Makefile.am b/Makefile.am
index 808fce77d..023f7e45a 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1256,6 +1256,7 @@ MIXER_API_SRC = \
 	src/mixer/MixerInternal.hxx
 
 libmixer_plugins_a_SOURCES = \
+	src/mixer/plugins/NullMixerPlugin.cxx \
 	src/mixer/plugins/SoftwareMixerPlugin.cxx \
 	src/mixer/plugins/SoftwareMixerPlugin.hxx
 libmixer_plugins_a_CPPFLAGS = $(AM_CPPFLAGS) \
diff --git a/NEWS b/NEWS
index b956c3881..31a034763 100644
--- a/NEWS
+++ b/NEWS
@@ -7,6 +7,8 @@ ver 0.20 (not yet released)
   - ape: drop support for non-standard tag "album artist"
 * output
   - pulse: set channel map to WAVE-EX
+* mixer
+  - null: new plugin
 * reset song priority on playback
 
 ver 0.19.5 (2014/11/26)
diff --git a/doc/user.xml b/doc/user.xml
index bc43a4167..920454377 100644
--- a/doc/user.xml
+++ b/doc/user.xml
@@ -572,7 +572,7 @@ systemctl start mpd.socket</programlisting>
             <row>
               <entry>
                 <varname>mixer_type</varname>
-                <parameter>hardware|software|none</parameter>
+                <parameter>hardware|software|null|none</parameter>
               </entry>
               <entry>
                 Specifies which mixer should be used for this audio
@@ -580,7 +580,9 @@ systemctl start mpd.socket</programlisting>
                 linkend="alsa_output">ALSA</link>, <link
                 linkend="oss_output">OSS</link> and <link
                 linkend="pulse_output">PulseAudio</link>), the
-                software mixer or no mixer
+                software mixer, the "null" mixer
+                (<parameter>null</parameter>; allows setting the
+                volume, but with no effect) or no mixer
                 (<parameter>none</parameter>).  By default, the
                 hardware mixer is used for devices which support it,
                 and none for the others.
diff --git a/src/mixer/MixerList.hxx b/src/mixer/MixerList.hxx
index e75b2e6ff..8be74adf2 100644
--- a/src/mixer/MixerList.hxx
+++ b/src/mixer/MixerList.hxx
@@ -27,6 +27,7 @@
 
 struct MixerPlugin;
 
+extern const MixerPlugin null_mixer_plugin;
 extern const MixerPlugin software_mixer_plugin;
 extern const MixerPlugin alsa_mixer_plugin;
 extern const MixerPlugin oss_mixer_plugin;
diff --git a/src/mixer/MixerType.cxx b/src/mixer/MixerType.cxx
index 0605f0979..8972118e5 100644
--- a/src/mixer/MixerType.cxx
+++ b/src/mixer/MixerType.cxx
@@ -34,6 +34,8 @@ mixer_type_parse(const char *input)
 		return MixerType::HARDWARE;
 	else if (strcmp(input, "software") == 0)
 		return MixerType::SOFTWARE;
+	else if (strcmp(input, "null") == 0)
+		return MixerType::NULL_;
 	else
 		return MixerType::UNKNOWN;
 }
diff --git a/src/mixer/MixerType.hxx b/src/mixer/MixerType.hxx
index 9831e3db6..40f60203d 100644
--- a/src/mixer/MixerType.hxx
+++ b/src/mixer/MixerType.hxx
@@ -27,6 +27,9 @@ enum class MixerType {
 	/** mixer disabled */
 	NONE,
 
+	/** "null" mixer (virtual fake) */
+	NULL_,
+
 	/** software mixer with pcm_volume() */
 	SOFTWARE,
 
diff --git a/src/mixer/plugins/NullMixerPlugin.cxx b/src/mixer/plugins/NullMixerPlugin.cxx
new file mode 100644
index 000000000..b8894d443
--- /dev/null
+++ b/src/mixer/plugins/NullMixerPlugin.cxx
@@ -0,0 +1,67 @@
+/*
+ * 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 "mixer/MixerInternal.hxx"
+
+class NullMixer final : public Mixer {
+	/**
+	 * The current volume in percent (0..100).
+	 */
+	unsigned volume;
+
+public:
+	NullMixer(MixerListener &_listener)
+		:Mixer(null_mixer_plugin, _listener),
+		 volume(100)
+	{
+	}
+
+	/* virtual methods from class Mixer */
+	bool Open(gcc_unused Error &error) override {
+		return true;
+	}
+
+	void Close() override {
+	}
+
+	int GetVolume(gcc_unused Error &error) override {
+		return volume;
+	}
+
+	bool SetVolume(unsigned _volume, gcc_unused Error &error) override {
+		volume = _volume;
+		return true;
+	}
+};
+
+static Mixer *
+null_mixer_init(gcc_unused EventLoop &event_loop,
+		gcc_unused AudioOutput &ao,
+		MixerListener &listener,
+		gcc_unused const config_param &param,
+		gcc_unused Error &error)
+{
+	return new NullMixer(listener);
+}
+
+const MixerPlugin null_mixer_plugin = {
+	null_mixer_init,
+	true,
+};
diff --git a/src/output/Init.cxx b/src/output/Init.cxx
index 3518c5c64..9418b6414 100644
--- a/src/output/Init.cxx
+++ b/src/output/Init.cxx
@@ -126,6 +126,10 @@ audio_output_load_mixer(EventLoop &event_loop, AudioOutput &ao,
 	case MixerType::UNKNOWN:
 		return nullptr;
 
+	case MixerType::NULL_:
+		return mixer_new(event_loop, null_mixer_plugin, ao, listener,
+				 param, error);
+
 	case MixerType::HARDWARE:
 		if (plugin == nullptr)
 			return nullptr;