-int mixer_control(int attribute((unused)) *left,
- int attribute((unused)) *right,
- int attribute((unused)) set) {
- error(0, "don't know how to set volume on this platform");
- return -1;
+/** @brief Get/set volume
+ * @param api Sound api or -1 for default
+ * @param left Left channel level, 0-100
+ * @param right Right channel level, 0-100
+ * @param set Set volume if non-0
+ * @return 0 on success, non-0 on error
+ *
+ * If getting the volume then @p left and @p right are filled in.
+ *
+ * If setting the volume then the target levels are read from @p left and
+ * @p right, and the actual level set is stored in them.
+ */
+int mixer_control(int api, int *left, int *right, int set) {
+ const struct mixer *const m = find_mixer(api);
+
+ /* We impose defaults bizarrely late, but this has the advantage of
+ * not making everything depend on sound libraries */
+ if(!config->mixer)
+ config->mixer = xstrdup(m->device);
+ if(!config->channel)
+ config->channel = xstrdup(m->channel);
+ if(set)
+ return m->set(left, right);
+ else
+ return m->get(left, right);