diff options
author | Ashok Sidipotu <ashok.sidipotu@collabora.com> | 2023-12-07 14:14:01 +0100 |
---|---|---|
committer | Ashok Sidipotu <ashok.sidipotu@collabora.com> | 2023-12-08 13:12:14 +0100 |
commit | f6eb75678f6c08c4eb3fe232f814834319611ff7 (patch) | |
tree | 0da6c467fb0e2ffcbceb0ccdfe64fc2ef05cd11e /src/audiomixertest.c | |
parent | 82c1c0ab04219f9453f1b3a14a9754068e360583 (diff) |
audiomixer: Add gain controls
- Add Equalizer gain controls.
- Add a simple app to test the controls.
Bug-AGL: SPEC-4931
Change-Id: Ib33eb0e829747c401861e99acd67291462ec6a97
Signed-off-by: Ashok Sidipotu <ashok.sidipotu@collabora.com>
Diffstat (limited to 'src/audiomixertest.c')
-rw-r--r-- | src/audiomixertest.c | 329 |
1 files changed, 329 insertions, 0 deletions
diff --git a/src/audiomixertest.c b/src/audiomixertest.c new file mode 100644 index 0000000..ddb7ac9 --- /dev/null +++ b/src/audiomixertest.c @@ -0,0 +1,329 @@ +/* WirePlumber + * + * Copyright © 2023 Collabora Ltd. + * @author Ashok Sidipotu <ashok.sidipotu@collabora.com> + * + * SPDX-License-Identifier: MIT + */ + +#include <wp/wp.h> +#include <stdio.h> +#include <getopt.h> +#include <math.h> +#include "audiomixer.h" + +typedef struct _AudioMixerTest AudioMixerTest; + +struct _AudioMixerTest +{ + struct audiomixer *am; + WpCore *core; + const struct mixer_control **ctrls; + unsigned int nctrls; + GMainLoop *loop; +}; + +static void +audio_mixer_clear (AudioMixerTest *self) +{ + audiomixer_free (self->am); + g_clear_pointer (&self->loop, g_main_loop_unref); +} + +static gint +set_mute (AudioMixerTest *self, gint id) +{ + gint ret = -1; + gboolean mute = FALSE; + int i; + + for (i = 0; i < self->nctrls; i++) { + const struct mixer_control *ctrl = self->ctrls[i]; + if (id == i) { + + if (g_str_equal ("bass", ctrl->name) || g_str_equal ("treble", ctrl->name)) + g_warning ("mute cannot be applied for %s control", ctrl->name); + else { + /* toggle mute value */ + mute = (ctrl->mute) ? FALSE : TRUE; + audiomixer_change_mute (self->am, ctrl, mute); + ret = TRUE; + } + + break; + } + } + + return ret; +} + +static gint +set_gain (AudioMixerTest *self, gint id, gfloat gain) +{ + gint ret = -1; + int i; + + for (i = 0; i < self->nctrls; i++) { + const struct mixer_control *ctrl = self->ctrls[i]; + + if(id == i) { + + if (g_str_equal ("bass", ctrl->name) || g_str_equal ("treble", ctrl->name)) { + if (fabs (ctrl->gain - gain) < 0.000001) + g_warning ("gain already at requested level %f", ctrl->gain); + else { + audiomixer_change_gain (self->am, ctrl, gain); + ret = TRUE; + } + } + else + g_warning ("gain cannot be applied for %s control", ctrl->name); + + break; + } + } + + return ret; +} + +static gint +set_volume (AudioMixerTest *self, gint id, double vol) +{ + gint ret = -1; + int i; + + for (i = 0; i < self->nctrls; i++) { + const struct mixer_control *ctrl = self->ctrls[i]; + + if (id == i) { + if (g_str_equal ("bass", ctrl->name) || g_str_equal ("treble", ctrl->name)) + g_warning ("volume cannot be applied for %s control", ctrl->name); + else { + + if (fabs (ctrl->volume - vol) < 0.000001) + g_warning ("volume is already at requested level %f", ctrl->volume); + else { + audiomixer_change_volume (self->am, ctrl, (double)vol); + ret = TRUE; + } + + } + break; + } + } + + return ret; +} + +static void +print_ctrls (AudioMixerTest *self) +{ + const struct mixer_control **ctrls = self->ctrls; + unsigned int nctrls = self->nctrls; + int i; + + fprintf (stdout, "\nControls:"); + for (i = 0; i < nctrls; i++) { + const struct mixer_control *ctrl = ctrls[i]; + if (g_str_equal ("bass", ctrl->name) || g_str_equal ("treble", ctrl->name)) + fprintf(stdout, "\n%2d. %-25s [gain: %.2f]", i, ctrl->name, + ctrl->gain); + else + fprintf(stdout, "\n%2d. %-25s [vol: %.2f, mute:%d]", i, ctrl->name, + ctrl->volume, ctrl->mute); + } + fprintf (stdout, "\n"); +} + +static void +refresh_ctrls (AudioMixerTest *self) +{ + self->ctrls = audiomixer_get_active_controls (self->am, &self->nctrls); + print_ctrls (self); +} + +static void show_help (void) +{ + fprintf (stdout, + "\n" + " -h, --help Show this help\n" + " -p, --print-controls prints controls\n" + " -i, --id control id(serial#) of the control, take a look at the controls to get the id of control\n" + " Examples\n" + " audio-mixer-test -> prints the controls and help text\n" + " audio-mixer-test -p -> prints only the controls\n" + " -v, --set-volume set volume level for volume controls(all controls except bass and treble)\n" + " Examples\n" + " audio-mixer-test -v 0.2 -> sets volume of the 1st control with 0.2\n" + " audio-mixer-test -i 9 -v 0.2 -> sets volume of the 9th control with 0.2\n" + " -g, --set-gain gain level for gain controls like bass and treble\n" + " Examples\n" + " audio-mixer-test -i 11 -g 0.8 -> sets gain of the 11th control with 0.8\n" + " -m, --set-mute mute/unmute volume controls(all controls except bass and treble) takes no arguments\n" + " Examples\n" + " audio-mixer-test -m -> mutes the 1st control\n" + " audio-mixer-test -m -> unmutes the 1st control, if it is issued after the above command\n" + " audio-mixer-test -i 9 -m -> mutes 9th control (Multimedia) with 0.8\n"); +} + +static void +mixer_value_change_cb (void *data, + unsigned int change_mask, + const struct mixer_control *ctrl) +{ + AudioMixerTest *self = (AudioMixerTest *)data; + refresh_ctrls (self); + g_main_loop_quit (self->loop); +} + +static void +mixer_controls_changed (void *data) +{ + AudioMixerTest *self = (AudioMixerTest *)data; + g_main_loop_quit (self->loop); +} + +gint +main (gint argc, gchar **argv) +{ + AudioMixerTest self = { 0 }; + g_autoptr (GError) error = NULL; + gint c, ret = 0; + struct audiomixer_events audiomixer_events = { 0 }; + + gint id = -1; + double vol = 0.0; + gfloat gain = 0.0; + + self.loop = g_main_loop_new (NULL, FALSE); + + self.am = audiomixer_new (); + + if (!self.am) { + g_warning ("unable to open audiomixer"); + goto exit; + } + + audiomixer_lock (self.am); + ret = audiomixer_ensure_controls (self.am, 3); + audiomixer_unlock (self.am); + if (ret < 0) { + g_warning ("ensure controls failed"); + goto exit; + } + + audiomixer_events.controls_changed = mixer_controls_changed; + audiomixer_add_event_listener (self.am, &audiomixer_events, (void *)&self); + + g_debug ("waiting for controls to be available"); + + do { + self.ctrls = audiomixer_get_active_controls (self.am, &self.nctrls); + + /* + * not a clean check but it appears like this is the best we can do at the + * moment. + */ + if (self.nctrls <= 4) + /* end points are not registered, wait for them to show up */ + g_main_loop_run (self.loop); + else + break; + + } while (1); + + if (argc == 1) { + print_ctrls (&self); + show_help (); + return 0; + } + + audiomixer_events.value_changed = mixer_value_change_cb; + audiomixer_add_event_listener (self.am, &audiomixer_events, (void *)&self); + + static const struct option long_options[] = { + { "help", no_argument, NULL, 'h' }, + { "print-controls", no_argument, NULL, 'p' }, + { "id", required_argument, NULL, 'i' }, + { "set-volume", required_argument, NULL, 'v' }, + { "set-mute", no_argument, NULL, 'm' }, + { "set-gain", required_argument, NULL, 'g' }, + { NULL, 0, NULL, 0} + }; + + while ((c = getopt_long (argc, argv, "hpi:v:mg:", long_options, NULL)) != -1) { + switch(c) { + case 'h': + show_help (); + break; + + case 'p': + print_ctrls (&self); + break; + + case 'i': + id = atoi (optarg); + if (!(id >= 0 && id < self.nctrls)) { + ret = -1; + g_warning ("id(%d) is invalid", id); + } + break; + + case 'v': + vol = (double)atof (optarg); + if (id == -1) { + g_warning ("control id not given defaulting it to 0(Master Playback)"); + id = 0; + } + + ret = set_volume (&self, id, vol); + if (ret != TRUE) + g_warning ("set-volume failed"); + else + /* wait for volume to be acked */ + g_main_loop_run (self.loop); + + break; + + case 'm': + if (id == -1) { + g_warning ("control id not given defaulting it to 0(Master Playback)"); + id = 0; + } + + ret = set_mute (&self, id); + if (ret != TRUE) + g_warning ("set-mute failed"); + else + /* wait for mute to be acked */ + g_main_loop_run (self.loop); + + break; + + case 'g': + gain = atof (optarg); + if (id == -1) { + g_warning ("control id not given defaulting it to 11(bass)"); + id = 11; /* bass ctrl */ + } + + ret = set_gain (&self, id, gain); + if (ret != TRUE) + g_warning ("set-gain failed"); + else + /* wait for gain to be acked */ + g_main_loop_run (self.loop); + + break; + + default: + show_help (); + break; + } + } + +exit: + /* clean up at program exit */ + audio_mixer_clear (&self); + return ret; +} |