Page 1 of 1

Output Volume

Posted: September 8th, 2015, 12:20 pm
by Bobboau
I would like to be able to set output volumes independently of each other. So if I have two outputs A and B I would like to be able to set B to be 50% via a client (as a protocol command I would presume). Ideally I would think this would work as if I set the normal volume to 50% and A was at 100% then the actual volume coming out of my two outputs would be A:50% and B:25%. I don't think there is a way to do this right now, am I wrong? is there a way? if not I would think adding an optional parameter to setvol or having a separate command (like maybe setoutputvol) which requires an output id in addition to a volume level would be a good candidate interface, but I have no idea how difficult that would be to implement and I would guess it would be pretty low on the priorities. I'm trying to setup a zoned sound system and this is really the biggest fly in my ointment at the moment, I can only seem to turn outputs on or off, but not control how loud they are in a direct manner (I can change volume system wide, and I can sort of stairstep relative volume, but this is far from ideal).

suggestions? thoughts?

Re: Output Volume

Posted: September 8th, 2015, 5:09 pm
by max
There's no way to do that currently, but it would be a good feature.

Re: Output Volume

Posted: October 3rd, 2015, 1:46 am
by Bobboau
Well, I made a feature request in the bugtracker a while ago, with no response yet.

Just to see what would be involved I hacked the source a bit tonight, and made an implementation of this. From looking around the source I can bet I've missed some function call for notifying something somewhere or didn't use the right wrapping method, but at the very least I think it shows this is feasible.

Here's a patch if anyone is interested.
Maybe someone who knows what they are doing can tell me what I got wrong
(would have attached as a file, but I can't find an extension the forum software likes)

Code: Select all

diff --git a/src/command/AllCommands.cxx b/src/command/AllCommands.cxx
index 8e8865f..40e5e1f 100644
--- a/src/command/AllCommands.cxx
+++ b/src/command/AllCommands.cxx
@@ -134,6 +134,7 @@ static constexpr struct command commands[] = {
 	{ "next", PERMISSION_CONTROL, 0, 0, handle_next },
 	{ "notcommands", PERMISSION_NONE, 0, 0, handle_not_commands },
 	{ "outputs", PERMISSION_READ, 0, 0, handle_devices },
+	{ "outputvolume", PERMISSION_ADMIN, 2, 2, handle_outputvolume },
 	{ "password", PERMISSION_NONE, 1, 1, handle_password },
 	{ "pause", PERMISSION_CONTROL, 0, 1, handle_pause },
 	{ "ping", PERMISSION_NONE, 0, 0, handle_ping },
diff --git a/src/command/OutputCommands.cxx b/src/command/OutputCommands.cxx
index 7bbe5f9..654b8cc 100644
--- a/src/command/OutputCommands.cxx
+++ b/src/command/OutputCommands.cxx
@@ -83,3 +83,33 @@ handle_devices(Client &client, gcc_unused Request args, Response &r)
 	printAudioDevices(r, client.partition.outputs);
 	return CommandResult::OK;
 }
+
+CommandResult
+handle_outputvolume(Client &client, Request args, Response &r)
+{
+	assert(args.size == 2);
+	unsigned device;
+	if (!args.Parse(0, device, r))
+		return CommandResult::ERROR;
+
+	if (device > client.partition.outputs.Size()-1 || device < 0) {
+		r.Error(ACK_ERROR_NO_EXIST, "No such audio output");
+		return CommandResult::ERROR;
+	}
+
+	unsigned volume;
+	if (!args.Parse(1, volume, r))
+		return CommandResult::ERROR;
+
+	if (volume > 100 || volume < 0) {
+		r.Error(ACK_ERROR_NO_EXIST, "volume must be in the range 0 - 100");
+		return CommandResult::ERROR;
+	}
+
+	if (!audio_output_set_volume(client.partition.outputs, device, volume)) {
+		r.Error(ACK_ERROR_NO_EXIST, "could not set volume on the output");
+		return CommandResult::ERROR;
+	}
+
+	return CommandResult::OK;
+}
diff --git a/src/command/OutputCommands.hxx b/src/command/OutputCommands.hxx
index 3dd81bc..0673e59 100644
--- a/src/command/OutputCommands.hxx
+++ b/src/command/OutputCommands.hxx
@@ -38,4 +38,7 @@ handle_toggleoutput(Client &client, Request request, Response &response);
 CommandResult
 handle_devices(Client &client, Request request, Response &response);
 
+CommandResult
+handle_outputvolume(Client &client, Request request, Response &response);
+
 #endif
diff --git a/src/output/OutputCommand.cxx b/src/output/OutputCommand.cxx
index 83abcf2..7d0fedd 100644
--- a/src/output/OutputCommand.cxx
+++ b/src/output/OutputCommand.cxx
@@ -31,6 +31,8 @@
 #include "player/Control.hxx"
 #include "mixer/MixerControl.hxx"
 #include "Idle.hxx"
+#include "mixer/MixerInternal.hxx"
+#include "util/Error.hxx"
 
 extern unsigned audio_output_state_version;
 
@@ -104,3 +106,30 @@ audio_output_toggle_index(MultipleOutputs &outputs, unsigned idx)
 
 	return true;
 }
+
+bool
+audio_output_set_volume(MultipleOutputs &outputs, unsigned idx, unsigned volume)
+{
+	if (idx >= outputs.Size())
+		return false;
+
+	AudioOutput &ao = outputs.Get(idx);
+	if (ao.mixer) {
+		bool it_worked = mixer_set_volume(ao.mixer, volume, IgnoreError());
+		if (!it_worked) {
+			return false;
+		}
+	}
+	else {
+		return false;
+	}
+
+	idle_add(IDLE_MIXER);
+	idle_add(IDLE_OUTPUT);
+
+	ao.player_control->UpdateAudio();
+
+	++audio_output_state_version;
+
+	return true;
+}
diff --git a/src/output/OutputCommand.hxx b/src/output/OutputCommand.hxx
index 5b53cd1..e0918b2 100644
--- a/src/output/OutputCommand.hxx
+++ b/src/output/OutputCommand.hxx
@@ -50,4 +50,11 @@ audio_output_disable_index(MultipleOutputs &outputs, unsigned idx);
 bool
 audio_output_toggle_index(MultipleOutputs &outputs, unsigned idx);
 
+/**
+ * Sets the volume of an audio output.  Returns false if the specified output
+ * does not exist, or if it's volume cannot be set.
+ */
+bool
+audio_output_set_volume(MultipleOutputs &outputs, unsigned idx, unsigned volume);
+
 #endif
diff --git a/src/output/OutputPrint.cxx b/src/output/OutputPrint.cxx
index d2ddbbf..26916f9 100644
--- a/src/output/OutputPrint.cxx
+++ b/src/output/OutputPrint.cxx
@@ -27,6 +27,8 @@
 #include "MultipleOutputs.hxx"
 #include "Internal.hxx"
 #include "client/Response.hxx"
+#include "mixer/MixerInternal.hxx"
+#include "util/Error.hxx"
 
 void
 printAudioDevices(Response &r, const MultipleOutputs &outputs)
@@ -38,5 +40,15 @@ printAudioDevices(Response &r, const MultipleOutputs &outputs)
 			 "outputname: %s\n"
 			 "outputenabled: %i\n",
 			 i, ao.name, ao.enabled);
+
+		//if they have independent volume report it
+		if(ao.mixer)
+		{
+			int volume = ao.mixer->GetVolume(IgnoreError());
+			if(volume > -1) //-1 indicates an error state
+			{
+				r.Format("outputvolume: %i\n",volume);
+			}
+		}
 	}
 }

Re: Output Volume

Posted: October 16th, 2015, 3:33 pm
by max
Submit this to the developer mailing list. On the forum, it's hard to review code and very cumbersome to apply a patch from.

Re: Output Volume

Posted: March 29th, 2016, 4:54 pm
by andyclimb
I came here specifically to look for / ask for this feature.. + 1 please