diff options
Diffstat (limited to 'src/mixer')
-rw-r--r-- | src/mixer/MixerAll.cxx | 175 | ||||
-rw-r--r-- | src/mixer/MixerAll.hxx | 64 | ||||
-rw-r--r-- | src/mixer/MixerControl.cxx | 161 | ||||
-rw-r--r-- | src/mixer/MixerControl.hxx | 60 | ||||
-rw-r--r-- | src/mixer/MixerInternal.hxx | 59 | ||||
-rw-r--r-- | src/mixer/MixerList.hxx | 35 | ||||
-rw-r--r-- | src/mixer/MixerPlugin.hxx | 95 | ||||
-rw-r--r-- | src/mixer/MixerType.cxx | 39 | ||||
-rw-r--r-- | src/mixer/MixerType.hxx | 47 | ||||
-rw-r--r-- | src/mixer/Volume.cxx | 130 | ||||
-rw-r--r-- | src/mixer/Volume.hxx | 49 | ||||
-rw-r--r-- | src/mixer/plugins/AlsaMixerPlugin.cxx (renamed from src/mixer/AlsaMixerPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/mixer/plugins/OssMixerPlugin.cxx (renamed from src/mixer/OssMixerPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/mixer/plugins/PulseMixerPlugin.cxx (renamed from src/mixer/PulseMixerPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/mixer/plugins/PulseMixerPlugin.hxx (renamed from src/mixer/PulseMixerPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/mixer/plugins/RoarMixerPlugin.cxx (renamed from src/mixer/RoarMixerPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/mixer/plugins/SoftwareMixerPlugin.cxx (renamed from src/mixer/SoftwareMixerPlugin.cxx) | 2 | ||||
-rw-r--r-- | src/mixer/plugins/SoftwareMixerPlugin.hxx (renamed from src/mixer/SoftwareMixerPlugin.hxx) | 0 | ||||
-rw-r--r-- | src/mixer/plugins/WinmmMixerPlugin.cxx (renamed from src/mixer/WinmmMixerPlugin.cxx) | 2 |
19 files changed, 920 insertions, 6 deletions
diff --git a/src/mixer/MixerAll.cxx b/src/mixer/MixerAll.cxx new file mode 100644 index 000000000..3cc92baee --- /dev/null +++ b/src/mixer/MixerAll.cxx @@ -0,0 +1,175 @@ +/* + * 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 "MixerAll.hxx" +#include "MixerControl.hxx" +#include "MixerInternal.hxx" +#include "MixerList.hxx" +#include "output/OutputAll.hxx" +#include "output/OutputInternal.hxx" +#include "pcm/Volume.hxx" +#include "util/Error.hxx" +#include "util/Domain.hxx" +#include "Log.hxx" + +#include <assert.h> + +static constexpr Domain mixer_domain("mixer"); + +static int +output_mixer_get_volume(unsigned i) +{ + struct audio_output *output; + int volume; + + assert(i < audio_output_count()); + + output = audio_output_get(i); + if (!output->enabled) + return -1; + + Mixer *mixer = output->mixer; + if (mixer == nullptr) + return -1; + + Error error; + volume = mixer_get_volume(mixer, error); + if (volume < 0 && error.IsDefined()) + FormatError(error, + "Failed to read mixer for '%s'", + output->name); + + return volume; +} + +int +mixer_all_get_volume(void) +{ + unsigned count = audio_output_count(), ok = 0; + int volume, total = 0; + + for (unsigned i = 0; i < count; i++) { + volume = output_mixer_get_volume(i); + if (volume >= 0) { + total += volume; + ++ok; + } + } + + if (ok == 0) + return -1; + + return total / ok; +} + +static bool +output_mixer_set_volume(unsigned i, unsigned volume) +{ + struct audio_output *output; + bool success; + + assert(i < audio_output_count()); + assert(volume <= 100); + + output = audio_output_get(i); + if (!output->enabled) + return false; + + Mixer *mixer = output->mixer; + if (mixer == nullptr) + return false; + + Error error; + success = mixer_set_volume(mixer, volume, error); + if (!success && error.IsDefined()) + FormatError(error, + "Failed to set mixer for '%s'", + output->name); + + return success; +} + +bool +mixer_all_set_volume(unsigned volume) +{ + bool success = false; + unsigned count = audio_output_count(); + + assert(volume <= 100); + + for (unsigned i = 0; i < count; i++) + success = output_mixer_set_volume(i, volume) + || success; + + return success; +} + +static int +output_mixer_get_software_volume(unsigned i) +{ + struct audio_output *output; + + assert(i < audio_output_count()); + + output = audio_output_get(i); + if (!output->enabled) + return -1; + + Mixer *mixer = output->mixer; + if (mixer == nullptr || !mixer->IsPlugin(software_mixer_plugin)) + return -1; + + return mixer_get_volume(mixer, IgnoreError()); +} + +int +mixer_all_get_software_volume(void) +{ + unsigned count = audio_output_count(), ok = 0; + int volume, total = 0; + + for (unsigned i = 0; i < count; i++) { + volume = output_mixer_get_software_volume(i); + if (volume >= 0) { + total += volume; + ++ok; + } + } + + if (ok == 0) + return -1; + + return total / ok; +} + +void +mixer_all_set_software_volume(unsigned volume) +{ + unsigned count = audio_output_count(); + + assert(volume <= PCM_VOLUME_1); + + for (unsigned i = 0; i < count; i++) { + struct audio_output *output = audio_output_get(i); + if (output->mixer != nullptr && + output->mixer->plugin == &software_mixer_plugin) + mixer_set_volume(output->mixer, volume, IgnoreError()); + } +} diff --git a/src/mixer/MixerAll.hxx b/src/mixer/MixerAll.hxx new file mode 100644 index 000000000..f868f64b5 --- /dev/null +++ b/src/mixer/MixerAll.hxx @@ -0,0 +1,64 @@ +/* + * 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. + */ + +/** \file + * + * Functions which affect the mixers of all audio outputs. + */ + +#ifndef MPD_MIXER_ALL_HXX +#define MPD_MIXER_ALL_HXX + +#include "Compiler.h" + +/** + * Returns the average volume of all available mixers (range 0..100). + * Returns -1 if no mixer can be queried. + */ +gcc_pure +int +mixer_all_get_volume(void); + +/** + * Sets the volume on all available mixers. + * + * @param volume the volume (range 0..100) + * @return true on success, false on failure + */ +bool +mixer_all_set_volume(unsigned volume); + +/** + * Similar to mixer_all_get_volume(), but gets the volume only for + * software mixers. See #software_mixer_plugin. This function fails + * if no software mixer is configured. + */ +gcc_pure +int +mixer_all_get_software_volume(void); + +/** + * Similar to mixer_all_set_volume(), but sets the volume only for + * software mixers. See #software_mixer_plugin. This function cannot + * fail, because the underlying software mixers cannot fail either. + */ +void +mixer_all_set_software_volume(unsigned volume); + +#endif diff --git a/src/mixer/MixerControl.cxx b/src/mixer/MixerControl.cxx new file mode 100644 index 000000000..bdf6fcc2b --- /dev/null +++ b/src/mixer/MixerControl.cxx @@ -0,0 +1,161 @@ +/* + * 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 "MixerControl.hxx" +#include "MixerInternal.hxx" +#include "util/Error.hxx" + +#include <assert.h> + +Mixer * +mixer_new(const struct mixer_plugin *plugin, void *ao, + const config_param ¶m, + Error &error) +{ + Mixer *mixer; + + assert(plugin != nullptr); + + mixer = plugin->init(ao, param, error); + + assert(mixer == nullptr || mixer->IsPlugin(*plugin)); + + return mixer; +} + +void +mixer_free(Mixer *mixer) +{ + assert(mixer != nullptr); + assert(mixer->plugin != nullptr); + + /* mixers with the "global" flag set might still be open at + this point (see mixer_auto_close()) */ + mixer_close(mixer); + + mixer->plugin->finish(mixer); +} + +bool +mixer_open(Mixer *mixer, Error &error) +{ + bool success; + + assert(mixer != nullptr); + assert(mixer->plugin != nullptr); + + const ScopeLock protect(mixer->mutex); + + if (mixer->open) + success = true; + else if (mixer->plugin->open == nullptr) + success = mixer->open = true; + else + success = mixer->open = mixer->plugin->open(mixer, error); + + mixer->failed = !success; + + return success; +} + +static void +mixer_close_internal(Mixer *mixer) +{ + assert(mixer != nullptr); + assert(mixer->plugin != nullptr); + assert(mixer->open); + + if (mixer->plugin->close != nullptr) + mixer->plugin->close(mixer); + + mixer->open = false; +} + +void +mixer_close(Mixer *mixer) +{ + assert(mixer != nullptr); + assert(mixer->plugin != nullptr); + + const ScopeLock protect(mixer->mutex); + + if (mixer->open) + mixer_close_internal(mixer); +} + +void +mixer_auto_close(Mixer *mixer) +{ + if (!mixer->plugin->global) + mixer_close(mixer); +} + +/* + * Close the mixer due to failure. The mutex must be locked before + * calling this function. + */ +static void +mixer_failed(Mixer *mixer) +{ + assert(mixer->open); + + mixer_close_internal(mixer); + + mixer->failed = true; +} + +int +mixer_get_volume(Mixer *mixer, Error &error) +{ + int volume; + + assert(mixer != nullptr); + + if (mixer->plugin->global && !mixer->failed && + !mixer_open(mixer, error)) + return -1; + + const ScopeLock protect(mixer->mutex); + + if (mixer->open) { + volume = mixer->plugin->get_volume(mixer, error); + if (volume < 0 && error.IsDefined()) + mixer_failed(mixer); + } else + volume = -1; + + return volume; +} + +bool +mixer_set_volume(Mixer *mixer, unsigned volume, Error &error) +{ + assert(mixer != nullptr); + assert(volume <= 100); + + if (mixer->plugin->global && !mixer->failed && + !mixer_open(mixer, error)) + return false; + + const ScopeLock protect(mixer->mutex); + + return mixer->open && + mixer->plugin->set_volume(mixer, volume, error); +} diff --git a/src/mixer/MixerControl.hxx b/src/mixer/MixerControl.hxx new file mode 100644 index 000000000..caa1c3054 --- /dev/null +++ b/src/mixer/MixerControl.hxx @@ -0,0 +1,60 @@ +/* + * 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. + */ + +/** \file + * + * Functions which manipulate a #mixer object. + */ + +#ifndef MPD_MIXER_CONTROL_HXX +#define MPD_MIXER_CONTROL_HXX + +class Error; +class Mixer; +struct mixer_plugin; +struct config_param; + +Mixer * +mixer_new(const mixer_plugin *plugin, void *ao, + const config_param ¶m, + Error &error); + +void +mixer_free(Mixer *mixer); + +bool +mixer_open(Mixer *mixer, Error &error); + +void +mixer_close(Mixer *mixer); + +/** + * Close the mixer unless the plugin's "global" flag is set. This is + * called when the #audio_output is closed. + */ +void +mixer_auto_close(Mixer *mixer); + +int +mixer_get_volume(Mixer *mixer, Error &error); + +bool +mixer_set_volume(Mixer *mixer, unsigned volume, Error &error); + +#endif diff --git a/src/mixer/MixerInternal.hxx b/src/mixer/MixerInternal.hxx new file mode 100644 index 000000000..1732b4f3b --- /dev/null +++ b/src/mixer/MixerInternal.hxx @@ -0,0 +1,59 @@ +/* + * 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. + */ + +#ifndef MPD_MIXER_INTERNAL_HXX +#define MPD_MIXER_INTERNAL_HXX + +#include "MixerPlugin.hxx" +#include "MixerList.hxx" +#include "thread/Mutex.hxx" + +class Mixer { +public: + const struct mixer_plugin *plugin; + + /** + * This mutex protects all of the mixer struct, including its + * implementation, so plugins don't have to deal with that. + */ + Mutex mutex; + + /** + * Is the mixer device currently open? + */ + bool open; + + /** + * Has this mixer failed, and should not be reopened + * automatically? + */ + bool failed; + +public: + Mixer(const mixer_plugin &_plugin) + :plugin(&_plugin), + open(false), + failed(false) {} + + bool IsPlugin(const mixer_plugin &other) const { + return plugin == &other; + } +}; + +#endif diff --git a/src/mixer/MixerList.hxx b/src/mixer/MixerList.hxx new file mode 100644 index 000000000..eb3dba938 --- /dev/null +++ b/src/mixer/MixerList.hxx @@ -0,0 +1,35 @@ +/* + * 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. + */ + +/** \file + * + * This header provides "extern" declarations for all mixer plugins. + */ + +#ifndef MPD_MIXER_LIST_HXX +#define MPD_MIXER_LIST_HXX + +extern const struct mixer_plugin software_mixer_plugin; +extern const struct mixer_plugin alsa_mixer_plugin; +extern const struct mixer_plugin oss_mixer_plugin; +extern const struct mixer_plugin roar_mixer_plugin; +extern const struct mixer_plugin pulse_mixer_plugin; +extern const struct mixer_plugin winmm_mixer_plugin; + +#endif diff --git a/src/mixer/MixerPlugin.hxx b/src/mixer/MixerPlugin.hxx new file mode 100644 index 000000000..b29ecbab8 --- /dev/null +++ b/src/mixer/MixerPlugin.hxx @@ -0,0 +1,95 @@ +/* + * 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. + */ + +/** \file + * + * This header declares the mixer_plugin class. It should not be + * included directly; use MixerInternal.hxx instead in mixer + * implementations. + */ + +#ifndef MPD_MIXER_PLUGIN_HXX +#define MPD_MIXER_PLUGIN_HXX + +struct config_param; +class Mixer; +class Error; + +struct mixer_plugin { + /** + * Alocates and configures a mixer device. + * + * @param ao the pointer returned by audio_output_plugin.init + * @param param the configuration section + * @param error_r location to store the error occurring, or + * nullptr to ignore errors + * @return a mixer object, or nullptr on error + */ + Mixer *(*init)(void *ao, const config_param ¶m, + Error &error); + + /** + * Finish and free mixer data + */ + void (*finish)(Mixer *data); + + /** + * Open mixer device + * + * @param error_r location to store the error occurring, or + * nullptr to ignore errors + * @return true on success, false on error + */ + bool (*open)(Mixer *data, Error &error); + + /** + * Close mixer device + */ + void (*close)(Mixer *data); + + /** + * Reads the current volume. + * + * @param error_r location to store the error occurring, or + * nullptr to ignore errors + * @return the current volume (0..100 including) or -1 if + * unavailable or on error (error set, mixer will be closed) + */ + int (*get_volume)(Mixer *mixer, Error &error); + + /** + * Sets the volume. + * + * @param error_r location to store the error occurring, or + * nullptr to ignore errors + * @param volume the new volume (0..100 including) + * @return true on success, false on error + */ + bool (*set_volume)(Mixer *mixer, unsigned volume, + Error &error); + + /** + * If true, then the mixer is automatically opened, even if + * its audio output is not open. If false, then the mixer is + * disabled as long as its audio output is closed. + */ + bool global; +}; + +#endif diff --git a/src/mixer/MixerType.cxx b/src/mixer/MixerType.cxx new file mode 100644 index 000000000..cd45db0d9 --- /dev/null +++ b/src/mixer/MixerType.cxx @@ -0,0 +1,39 @@ +/* + * 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 "MixerType.hxx" + +#include <assert.h> +#include <string.h> + +enum mixer_type +mixer_type_parse(const char *input) +{ + assert(input != NULL); + + if (strcmp(input, "none") == 0 || strcmp(input, "disabled") == 0) + return MIXER_TYPE_NONE; + else if (strcmp(input, "hardware") == 0) + return MIXER_TYPE_HARDWARE; + else if (strcmp(input, "software") == 0) + return MIXER_TYPE_SOFTWARE; + else + return MIXER_TYPE_UNKNOWN; +} diff --git a/src/mixer/MixerType.hxx b/src/mixer/MixerType.hxx new file mode 100644 index 000000000..bfa2637b7 --- /dev/null +++ b/src/mixer/MixerType.hxx @@ -0,0 +1,47 @@ +/* + * 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. + */ + +#ifndef MPD_MIXER_TYPE_HXX +#define MPD_MIXER_TYPE_HXX + +enum mixer_type { + /** parser error */ + MIXER_TYPE_UNKNOWN, + + /** mixer disabled */ + MIXER_TYPE_NONE, + + /** software mixer with pcm_volume() */ + MIXER_TYPE_SOFTWARE, + + /** hardware mixer (output's plugin) */ + MIXER_TYPE_HARDWARE, +}; + +/** + * Parses a "mixer_type" setting from the configuration file. + * + * @param input the configured string value; must not be NULL + * @return a #mixer_type value; MIXER_TYPE_UNKNOWN means #input could + * not be parsed + */ +enum mixer_type +mixer_type_parse(const char *input); + +#endif diff --git a/src/mixer/Volume.cxx b/src/mixer/Volume.cxx new file mode 100644 index 000000000..4c897b21f --- /dev/null +++ b/src/mixer/Volume.cxx @@ -0,0 +1,130 @@ +/* + * 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 "Volume.hxx" +#include "MixerAll.hxx" +#include "Idle.hxx" +#include "GlobalEvents.hxx" +#include "util/StringUtil.hxx" +#include "util/Domain.hxx" +#include "system/PeriodClock.hxx" +#include "Log.hxx" + +#include <assert.h> +#include <stdlib.h> + +#define SW_VOLUME_STATE "sw_volume: " + +static constexpr Domain volume_domain("volume"); + +static unsigned volume_software_set = 100; + +/** the cached hardware mixer value; invalid if negative */ +static int last_hardware_volume = -1; +/** the age of #last_hardware_volume */ +static PeriodClock hardware_volume_clock; + +/** + * Handler for #GlobalEvents::MIXER. + */ +static void +mixer_event_callback(void) +{ + /* flush the hardware volume cache */ + last_hardware_volume = -1; + + /* notify clients */ + idle_add(IDLE_MIXER); +} + +void volume_init(void) +{ + GlobalEvents::Register(GlobalEvents::MIXER, mixer_event_callback); +} + +int volume_level_get(void) +{ + if (last_hardware_volume >= 0 && + !hardware_volume_clock.CheckUpdate(1000)) + /* throttle access to hardware mixers */ + return last_hardware_volume; + + last_hardware_volume = mixer_all_get_volume(); + return last_hardware_volume; +} + +static bool software_volume_change(unsigned volume) +{ + assert(volume <= 100); + + volume_software_set = volume; + mixer_all_set_software_volume(volume); + + return true; +} + +static bool hardware_volume_change(unsigned volume) +{ + /* reset the cache */ + last_hardware_volume = -1; + + return mixer_all_set_volume(volume); +} + +bool volume_level_change(unsigned volume) +{ + assert(volume <= 100); + + volume_software_set = volume; + + idle_add(IDLE_MIXER); + + return hardware_volume_change(volume); +} + +bool +read_sw_volume_state(const char *line) +{ + char *end = nullptr; + long int sv; + + if (!StringStartsWith(line, SW_VOLUME_STATE)) + return false; + + line += sizeof(SW_VOLUME_STATE) - 1; + sv = strtol(line, &end, 10); + if (*end == 0 && sv >= 0 && sv <= 100) + software_volume_change(sv); + else + FormatWarning(volume_domain, + "Can't parse software volume: %s", line); + return true; +} + +void save_sw_volume_state(FILE *fp) +{ + fprintf(fp, SW_VOLUME_STATE "%u\n", volume_software_set); +} + +unsigned +sw_volume_state_get_hash(void) +{ + return volume_software_set; +} diff --git a/src/mixer/Volume.hxx b/src/mixer/Volume.hxx new file mode 100644 index 000000000..06d3551eb --- /dev/null +++ b/src/mixer/Volume.hxx @@ -0,0 +1,49 @@ +/* + * 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. + */ + +#ifndef MPD_VOLUME_HXX +#define MPD_VOLUME_HXX + +#include "Compiler.h" + +#include <stdio.h> + +void volume_init(void); + +gcc_pure +int volume_level_get(void); + +bool volume_level_change(unsigned volume); + +bool +read_sw_volume_state(const char *line); + +void save_sw_volume_state(FILE *fp); + +/** + * Generates a hash number for the current state of the software + * volume control. This is used by timer_save_state_file() to + * determine whether the state has changed and the state file should + * be saved. + */ +gcc_pure +unsigned +sw_volume_state_get_hash(void); + +#endif diff --git a/src/mixer/AlsaMixerPlugin.cxx b/src/mixer/plugins/AlsaMixerPlugin.cxx index 9d04ad98b..a15820fc7 100644 --- a/src/mixer/AlsaMixerPlugin.cxx +++ b/src/mixer/plugins/AlsaMixerPlugin.cxx @@ -18,7 +18,7 @@ */ #include "config.h" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "output/OutputAPI.hxx" #include "GlobalEvents.hxx" #include "Main.hxx" diff --git a/src/mixer/OssMixerPlugin.cxx b/src/mixer/plugins/OssMixerPlugin.cxx index 4e116c2fb..095ace015 100644 --- a/src/mixer/OssMixerPlugin.cxx +++ b/src/mixer/plugins/OssMixerPlugin.cxx @@ -18,7 +18,7 @@ */ #include "config.h" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "config/ConfigData.hxx" #include "system/fd_util.h" #include "util/ASCII.hxx" diff --git a/src/mixer/PulseMixerPlugin.cxx b/src/mixer/plugins/PulseMixerPlugin.cxx index a379cebae..4df88d06b 100644 --- a/src/mixer/PulseMixerPlugin.cxx +++ b/src/mixer/plugins/PulseMixerPlugin.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "PulseMixerPlugin.hxx" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "output/plugins/PulseOutputPlugin.hxx" #include "GlobalEvents.hxx" #include "util/Error.hxx" diff --git a/src/mixer/PulseMixerPlugin.hxx b/src/mixer/plugins/PulseMixerPlugin.hxx index 993945e9b..993945e9b 100644 --- a/src/mixer/PulseMixerPlugin.hxx +++ b/src/mixer/plugins/PulseMixerPlugin.hxx diff --git a/src/mixer/RoarMixerPlugin.cxx b/src/mixer/plugins/RoarMixerPlugin.cxx index 18f8c14f8..958688cd7 100644 --- a/src/mixer/RoarMixerPlugin.cxx +++ b/src/mixer/plugins/RoarMixerPlugin.cxx @@ -20,7 +20,7 @@ #include "config.h" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "output/plugins/RoarOutputPlugin.hxx" #include "Compiler.h" diff --git a/src/mixer/SoftwareMixerPlugin.cxx b/src/mixer/plugins/SoftwareMixerPlugin.cxx index a0de727af..67ddee1a4 100644 --- a/src/mixer/SoftwareMixerPlugin.cxx +++ b/src/mixer/plugins/SoftwareMixerPlugin.cxx @@ -19,7 +19,7 @@ #include "config.h" #include "SoftwareMixerPlugin.hxx" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "filter/FilterPlugin.hxx" #include "filter/FilterRegistry.hxx" #include "filter/FilterInternal.hxx" diff --git a/src/mixer/SoftwareMixerPlugin.hxx b/src/mixer/plugins/SoftwareMixerPlugin.hxx index 581d2ac17..581d2ac17 100644 --- a/src/mixer/SoftwareMixerPlugin.hxx +++ b/src/mixer/plugins/SoftwareMixerPlugin.hxx diff --git a/src/mixer/WinmmMixerPlugin.cxx b/src/mixer/plugins/WinmmMixerPlugin.cxx index 6f10fd71b..093a026a9 100644 --- a/src/mixer/WinmmMixerPlugin.cxx +++ b/src/mixer/plugins/WinmmMixerPlugin.cxx @@ -18,7 +18,7 @@ */ #include "config.h" -#include "MixerInternal.hxx" +#include "mixer/MixerInternal.hxx" #include "output/OutputAPI.hxx" #include "output/plugins/WinmmOutputPlugin.hxx" #include "util/Error.hxx" |