From 69fa928f332005972e1993c2333632493dfbc40a Mon Sep 17 00:00:00 2001 From: "info@hifiberry.com" Date: Thu, 5 Mar 2020 14:35:03 +0100 Subject: [PATCH] Added implementing ALSA volume control --- src/main.c | 5 ++- src/output.c | 90 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/output.h | 7 +++- 3 files changed, 99 insertions(+), 3 deletions(-) diff --git a/src/main.c b/src/main.c index ef720e3..c6c0ee3 100644 --- a/src/main.c +++ b/src/main.c @@ -87,6 +87,7 @@ static const gchar *output = NULL; static const gchar *pid_file = NULL; static const gchar *log_file = NULL; static const gchar *mime_filter = NULL; +static const gchar *alsa_mixer = NULL; /* Generic GMediaRender options */ static GOptionEntry option_entries[] = { @@ -125,6 +126,8 @@ static GOptionEntry option_entries[] = { "Dump Rendering Control service description XML and exit.", NULL }, { "dump-transport-scpd", 0, 0, G_OPTION_ARG_NONE, &show_transport_scpd, "Dump A/V Transport service description XML and exit.", NULL }, + { "mixer", 0, 0, G_OPTION_ARG_STRING, &alsa_mixer, + "ALSA mixer control to use", NULL }, { NULL } }; @@ -283,7 +286,7 @@ int main(int argc, char **argv) return EXIT_FAILURE; } - rc = output_init(output); + rc = output_init(output, alsa_mixer); if (rc != 0) { Log_error("main", "ERROR: Failed to initialize Output subsystem"); diff --git a/src/output.c b/src/output.c index 6e30585..cbb51fc 100644 --- a/src/output.c +++ b/src/output.c @@ -52,6 +52,80 @@ static struct output_module *modules[] = { #endif }; +/** Additions: ALSA volume control **/ + +#include + +snd_mixer_elem_t* mixer_elem; +long mixer_max; +snd_mixer_t *mixer_handle; +snd_mixer_selem_id_t *mixer_sid; + +int init_alsa(const char *mixer_name) { + mixer_max = 0; + long min; + const char *card = "default"; + + if (! mixer_name) { + Log_info("alsa", "No mixer control defined, won't enable ALSA mixer control"); + return -1; + } + + snd_mixer_open(&mixer_handle, 0); + + if (! mixer_handle) { + Log_error("alsa", "Can't open mixer"); + return -1; + } + + snd_mixer_attach(mixer_handle, card); + snd_mixer_selem_register(mixer_handle, NULL, NULL); + snd_mixer_load(mixer_handle); + + snd_mixer_selem_id_alloca(&mixer_sid); + + if (! mixer_sid) { + Log_error("alsa", "Can't allocate mixer_sid"); + return -1; + } + + snd_mixer_selem_id_set_index(mixer_sid, 0); + snd_mixer_selem_id_set_name(mixer_sid, mixer_name); + mixer_elem = snd_mixer_find_selem(mixer_handle, mixer_sid); + + if (! mixer_elem) { + Log_error("alsa", "Mixer control %s does not exist", mixer_name); + return -1; + } + + snd_mixer_selem_get_playback_volume_range(mixer_elem, &min, &mixer_max); + + return 0; +} + +void close_alsa(void) { + snd_mixer_close(mixer_handle); +} + +int set_alsa_volume(float value) { + if (mixer_max <= 0) + return 0; + + long volume = value; + + if (!(snd_mixer_selem_set_playback_volume_all( + mixer_elem, volume * mixer_max / 100))) + return 0; + else + return 1; +} + +float get_alsa_volume(void) { + return -1; +} + +/************************************/ + static struct output_module *output_module = NULL; void output_dump_modules(void) @@ -72,10 +146,12 @@ void output_dump_modules(void) } } -int output_init(const char *shortname) +int output_init(const char *shortname, const char *alsa_mixer) { int count; + init_alsa(alsa_mixer); + count = sizeof(modules) / sizeof(struct output_module *); if (count == 0) { Log_error("output", "No output module available"); @@ -194,12 +270,24 @@ int output_get_position(gint64 *track_dur, gint64 *track_pos) { } int output_get_volume(float *value) { + /* Try ALSA first */ + float vol = get_alsa_volume(); + if (vol >= 0) { + return vol; + } + /* Go on if ALSA volume isn't supported */ if (output_module && output_module->get_volume) { return output_module->get_volume(value); } return -1; } int output_set_volume(float value) { + /* Try ALSA first */ + float vol = set_alsa_volume(value); + if (vol >= 0) { + return vol; + } + /* Go on if ALSA volume isn't supported */ if (output_module && output_module->set_volume) { return output_module->set_volume(value); } diff --git a/src/output.h b/src/output.h index 9230752..f34b92a 100644 --- a/src/output.h +++ b/src/output.h @@ -39,7 +39,12 @@ typedef void (*output_transition_cb_t)(enum PlayFeedback); // callback with changes we send back to the controlling layer. typedef void (*output_update_meta_cb_t)(const struct SongMetaData *); -int output_init(const char *shortname); +int init_alsa(const char *mixer_name); +void close_alsa(void); +int set_alsa_volume(float value); +float get_alsa_volume(void); + +int output_init(const char *shortname, const char *alsa_mixer); int output_add_options(GOptionContext *ctx); void output_dump_modules(void);