[pulseaudio-discuss] [PATCH 1/5] pactl: Allow to set volume of each channel independently (Bug #39190)
Peter Meerwald
pmeerw at pmeerw.net
Fri Feb 14 10:11:47 CET 2014
From: Parin Porecha <parinporecha at gmail.com>
Example: pactl set-sink-volume "sink_name" 32000 40000
If the number of volumes provided is different than the number of channels
(excluding the case where a single volume is provided), an error message
is displayed explaining why the volumes could not be set.
patch proposed by Parin Porecha, commit message slightly edited
---
src/utils/pactl.c | 183 ++++++++++++++++++++++++++++++++++++++----------------
1 file changed, 130 insertions(+), 53 deletions(-)
diff --git a/src/utils/pactl.c b/src/utils/pactl.c
index 40e6689..f199f77 100644
--- a/src/utils/pactl.c
+++ b/src/utils/pactl.c
@@ -69,7 +69,7 @@ static bool short_list_format = false;
static uint32_t module_index;
static int32_t latency_offset;
static bool suspend;
-static pa_volume_t volume;
+static pa_cvolume volume;
static enum volume_flags {
VOL_UINT = 0,
VOL_PERCENT = 1,
@@ -837,12 +837,17 @@ static void volume_relative_adjust(pa_cvolume *cv) {
/* Relative volume change is additive in case of UINT or PERCENT
* and multiplicative for LINEAR or DECIBEL */
if ((volume_flags & 0x0F) == VOL_UINT || (volume_flags & 0x0F) == VOL_PERCENT) {
- pa_volume_t v = pa_cvolume_avg(cv);
- v = v + volume < PA_VOLUME_NORM ? PA_VOLUME_MUTED : v + volume - PA_VOLUME_NORM;
- pa_cvolume_set(cv, 1, v);
+ unsigned i;
+ for (i = 0; i < cv->channels; i++)
+ {
+ if (cv->values[i] + volume.values[i] < PA_VOLUME_NORM)
+ cv->values[i] = PA_VOLUME_MUTED;
+ else
+ cv->values[i] += volume.values[i] - PA_VOLUME_NORM;
+ }
}
if ((volume_flags & 0x0F) == VOL_LINEAR || (volume_flags & 0x0F) == VOL_DECIBEL) {
- pa_sw_cvolume_multiply_scalar(cv, cv, volume);
+ pa_sw_cvolume_multiply(cv, cv, &volume);
}
}
@@ -873,6 +878,7 @@ static void unload_module_by_name_callback(pa_context *c, const pa_module_info *
static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int is_last, void *userdata) {
pa_cvolume cv;
+ unsigned channels_supported;
if (is_last < 0) {
pa_log(_("Failed to get sink information: %s"), pa_strerror(pa_context_errno(c)));
@@ -885,13 +891,29 @@ static void get_sink_volume_callback(pa_context *c, const pa_sink_info *i, int i
pa_assert(i);
- cv = i->volume;
- volume_relative_adjust(&cv);
+ channels_supported = (&i->channel_map)->channels;
+ if ((volume.channels < channels_supported && volume.channels != 1) || (volume.channels > channels_supported)) {
+ pa_log(_("Failed to set volume: You tried to set volumes for %d channels, whereas channel/s supported = %d\n"), volume.channels, channels_supported);
+ quit(1);
+ return;
+ }
+
+ if (volume.channels == 1)
+ pa_cvolume_set(&volume, channels_supported, volume.values[0]);
+ volume.channels = channels_supported;
+
+ if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+ cv = i->volume;
+ volume_relative_adjust(&cv);
+ }
+ else
+ cv = volume;
pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &cv, simple_callback, NULL));
}
static void get_source_volume_callback(pa_context *c, const pa_source_info *i, int is_last, void *userdata) {
pa_cvolume cv;
+ unsigned channels_supported;
if (is_last < 0) {
pa_log(_("Failed to get source information: %s"), pa_strerror(pa_context_errno(c)));
@@ -904,13 +926,29 @@ static void get_source_volume_callback(pa_context *c, const pa_source_info *i, i
pa_assert(i);
- cv = i->volume;
- volume_relative_adjust(&cv);
+ channels_supported = (&i->channel_map)->channels;
+ if ((volume.channels < channels_supported && volume.channels != 1) || (volume.channels > channels_supported)) {
+ pa_log(_("Failed to set volume: You tried to set volumes for %d channels, whereas channel/s supported = %d\n"), volume.channels, channels_supported);
+ quit(1);
+ return;
+ }
+
+ if (volume.channels == 1)
+ pa_cvolume_set(&volume, channels_supported, volume.values[0]);
+ volume.channels = channels_supported;
+
+ if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+ cv = i->volume;
+ volume_relative_adjust(&cv);
+ }
+ else
+ cv = volume;
pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &cv, simple_callback, NULL));
}
static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_info *i, int is_last, void *userdata) {
pa_cvolume cv;
+ unsigned channels_supported;
if (is_last < 0) {
pa_log(_("Failed to get sink input information: %s"), pa_strerror(pa_context_errno(c)));
@@ -923,13 +961,29 @@ static void get_sink_input_volume_callback(pa_context *c, const pa_sink_input_in
pa_assert(i);
- cv = i->volume;
- volume_relative_adjust(&cv);
+ channels_supported = (&i->channel_map)->channels;
+ if ((volume.channels < channels_supported && volume.channels != 1) || (volume.channels > channels_supported)) {
+ pa_log(_("Failed to set volume: You tried to set volumes for %d channels, whereas channel/s supported = %d\n"), volume.channels, channels_supported);
+ quit(1);
+ return;
+ }
+
+ if (volume.channels == 1)
+ pa_cvolume_set(&volume, channels_supported, volume.values[0]);
+ volume.channels = channels_supported;
+
+ if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+ cv = i->volume;
+ volume_relative_adjust(&cv);
+ }
+ else
+ cv = volume;
pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &cv, simple_callback, NULL));
}
static void get_source_output_volume_callback(pa_context *c, const pa_source_output_info *o, int is_last, void *userdata) {
pa_cvolume cv;
+ unsigned channels_supported;
if (is_last < 0) {
pa_log(_("Failed to get source output information: %s"), pa_strerror(pa_context_errno(c)));
@@ -942,8 +996,23 @@ static void get_source_output_volume_callback(pa_context *c, const pa_source_out
pa_assert(o);
- cv = o->volume;
- volume_relative_adjust(&cv);
+ channels_supported = (&o->channel_map)->channels;
+ if ((volume.channels < channels_supported && volume.channels != 1) || (volume.channels > channels_supported)) {
+ pa_log(_("Failed to set volume: You tried to set volumes for %d channels, whereas channel/s supported = %d\n"), volume.channels, channels_supported);
+ quit(1);
+ return;
+ }
+
+ if (volume.channels == 1)
+ pa_cvolume_set(&volume, channels_supported, volume.values[0]);
+ volume.channels = channels_supported;
+
+ if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
+ cv = o->volume;
+ volume_relative_adjust(&cv);
+ }
+ else
+ cv = volume;
pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &cv, simple_callback, NULL));
}
@@ -1309,43 +1378,19 @@ static void context_state_callback(pa_context *c, void *userdata) {
break;
case SET_SINK_VOLUME:
- if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
- pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
- } else {
- pa_cvolume v;
- pa_cvolume_set(&v, 1, volume);
- pa_operation_unref(pa_context_set_sink_volume_by_name(c, sink_name, &v, simple_callback, NULL));
- }
+ pa_operation_unref(pa_context_get_sink_info_by_name(c, sink_name, get_sink_volume_callback, NULL));
break;
case SET_SOURCE_VOLUME:
- if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
- pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
- } else {
- pa_cvolume v;
- pa_cvolume_set(&v, 1, volume);
- pa_operation_unref(pa_context_set_source_volume_by_name(c, source_name, &v, simple_callback, NULL));
- }
+ pa_operation_unref(pa_context_get_source_info_by_name(c, source_name, get_source_volume_callback, NULL));
break;
case SET_SINK_INPUT_VOLUME:
- if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
- pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
- } else {
- pa_cvolume v;
- pa_cvolume_set(&v, 1, volume);
- pa_operation_unref(pa_context_set_sink_input_volume(c, sink_input_idx, &v, simple_callback, NULL));
- }
+ pa_operation_unref(pa_context_get_sink_input_info(c, sink_input_idx, get_sink_input_volume_callback, NULL));
break;
case SET_SOURCE_OUTPUT_VOLUME:
- if ((volume_flags & VOL_RELATIVE) == VOL_RELATIVE) {
- pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL));
- } else {
- pa_cvolume v;
- pa_cvolume_set(&v, 1, volume);
- pa_operation_unref(pa_context_set_source_output_volume(c, source_output_idx, &v, simple_callback, NULL));
- }
+ pa_operation_unref(pa_context_get_source_output_info(c, source_output_idx, get_source_output_volume_callback, NULL));
break;
case SET_SINK_FORMATS:
@@ -1806,35 +1851,52 @@ int main(int argc, char *argv[]) {
source_name = pa_xstrdup(argv[optind+1]);
} else if (pa_streq(argv[optind], "set-sink-volume")) {
+ unsigned i=0;
action = SET_SINK_VOLUME;
- if (argc != optind+3) {
+ if (argc < optind+3) {
pa_log(_("You have to specify a sink name/index and a volume"));
goto quit;
}
sink_name = pa_xstrdup(argv[optind+1]);
- if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
- goto quit;
+ volume.channels = argc-3;
+
+ for(i=0; i < volume.channels; i++)
+ {
+ if (argv[optind+2+i] == NULL)
+ volume.channels--;
+ else if (parse_volume(argv[optind+2+i], &volume.values[i], &volume_flags) < 0)
+ goto quit;
+ }
} else if (pa_streq(argv[optind], "set-source-volume")) {
+ unsigned i=0;
action = SET_SOURCE_VOLUME;
- if (argc != optind+3) {
+ if (argc < optind+3) {
pa_log(_("You have to specify a source name/index and a volume"));
goto quit;
}
source_name = pa_xstrdup(argv[optind+1]);
- if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
- goto quit;
+ volume.channels = argc-3;
+
+ for(i=0; i < volume.channels; i++)
+ {
+ if (argv[optind+2+i] == NULL)
+ volume.channels--;
+ else if (parse_volume(argv[optind+2+i], &volume.values[i], &volume_flags) < 0)
+ goto quit;
+ }
} else if (pa_streq(argv[optind], "set-sink-input-volume")) {
+ unsigned i=0;
action = SET_SINK_INPUT_VOLUME;
- if (argc != optind+3) {
+ if (argc < optind+3) {
pa_log(_("You have to specify a sink input index and a volume"));
goto quit;
}
@@ -1844,13 +1906,21 @@ int main(int argc, char *argv[]) {
goto quit;
}
- if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
- goto quit;
+ volume.channels = argc-3;
+
+ for(i=0; i < volume.channels; i++)
+ {
+ if (argv[optind+2+i] == NULL)
+ volume.channels--;
+ else if (parse_volume(argv[optind+2+i], &volume.values[i], &volume_flags) < 0)
+ goto quit;
+ }
} else if (pa_streq(argv[optind], "set-source-output-volume")) {
+ unsigned i=0;
action = SET_SOURCE_OUTPUT_VOLUME;
- if (argc != optind+3) {
+ if (argc < optind+3) {
pa_log(_("You have to specify a source output index and a volume"));
goto quit;
}
@@ -1860,8 +1930,15 @@ int main(int argc, char *argv[]) {
goto quit;
}
- if (parse_volume(argv[optind+2], &volume, &volume_flags) < 0)
- goto quit;
+ volume.channels = argc-3;
+
+ for(i=0; i < volume.channels; i++)
+ {
+ if (argv[optind+2+i] == NULL)
+ volume.channels--;
+ else if (parse_volume(argv[optind+2+i], &volume.values[i], &volume_flags) < 0)
+ goto quit;
+ }
} else if (pa_streq(argv[optind], "set-sink-mute")) {
action = SET_SINK_MUTE;
--
1.8.3.2
More information about the pulseaudio-discuss
mailing list