mixer_plugin: use GError for error handling
This commit is contained in:
parent
9cd2129eeb
commit
4e2fb3fb89
|
@ -42,8 +42,18 @@ struct alsa_mixer {
|
|||
int volume_set;
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
alsa_mixer_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("alsa_mixer");
|
||||
}
|
||||
|
||||
static struct mixer *
|
||||
alsa_mixer_init(const struct config_param *param)
|
||||
alsa_mixer_init(const struct config_param *param,
|
||||
G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct alsa_mixer *am = g_new(struct alsa_mixer, 1);
|
||||
|
||||
|
@ -81,7 +91,7 @@ alsa_mixer_close(struct mixer *data)
|
|||
}
|
||||
|
||||
static bool
|
||||
alsa_mixer_open(struct mixer *data)
|
||||
alsa_mixer_open(struct mixer *data, GError **error_r)
|
||||
{
|
||||
struct alsa_mixer *am = (struct alsa_mixer *)data;
|
||||
int err;
|
||||
|
@ -91,29 +101,33 @@ alsa_mixer_open(struct mixer *data)
|
|||
|
||||
err = snd_mixer_open(&am->handle, 0);
|
||||
if (err < 0) {
|
||||
g_warning("problems opening alsa mixer: %s\n", snd_strerror(err));
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"snd_mixer_open() failed: %s", snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((err = snd_mixer_attach(am->handle, am->device)) < 0) {
|
||||
g_warning("problems attaching alsa mixer: %s\n",
|
||||
snd_strerror(err));
|
||||
alsa_mixer_close(data);
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"failed to attach to %s: %s",
|
||||
am->device, snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((err = snd_mixer_selem_register(am->handle, NULL,
|
||||
NULL)) < 0) {
|
||||
g_warning("problems snd_mixer_selem_register'ing: %s\n",
|
||||
snd_strerror(err));
|
||||
alsa_mixer_close(data);
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"snd_mixer_selem_register() failed: %s",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((err = snd_mixer_load(am->handle)) < 0) {
|
||||
g_warning("problems snd_mixer_selem_register'ing: %s\n",
|
||||
snd_strerror(err));
|
||||
alsa_mixer_close(data);
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"snd_mixer_load() failed: %s\n",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -138,14 +152,14 @@ alsa_mixer_open(struct mixer *data)
|
|||
return true;
|
||||
}
|
||||
|
||||
g_warning("can't find alsa mixer control \"%s\"\n", am->control);
|
||||
|
||||
alsa_mixer_close(data);
|
||||
g_set_error(error_r, alsa_mixer_quark(), 0,
|
||||
"no such mixer control: %s", am->control);
|
||||
return false;
|
||||
}
|
||||
|
||||
static int
|
||||
alsa_mixer_get_volume(struct mixer *mixer)
|
||||
alsa_mixer_get_volume(struct mixer *mixer, GError **error_r)
|
||||
{
|
||||
struct alsa_mixer *am = (struct alsa_mixer *)mixer;
|
||||
int err;
|
||||
|
@ -156,8 +170,9 @@ alsa_mixer_get_volume(struct mixer *mixer)
|
|||
|
||||
err = snd_mixer_handle_events(am->handle);
|
||||
if (err < 0) {
|
||||
g_warning("problems getting alsa volume: %s (snd_mixer_%s)\n",
|
||||
snd_strerror(err), "handle_events");
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"snd_mixer_handle_events() failed: %s",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -165,8 +180,9 @@ alsa_mixer_get_volume(struct mixer *mixer)
|
|||
SND_MIXER_SCHN_FRONT_LEFT,
|
||||
&level);
|
||||
if (err < 0) {
|
||||
g_warning("problems getting alsa volume: %s (snd_mixer_%s)\n",
|
||||
snd_strerror(err), "selem_get_playback_volume");
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"failed to read ALSA volume: %s",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -183,7 +199,7 @@ alsa_mixer_get_volume(struct mixer *mixer)
|
|||
}
|
||||
|
||||
static bool
|
||||
alsa_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
||||
alsa_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
|
||||
{
|
||||
struct alsa_mixer *am = (struct alsa_mixer *)mixer;
|
||||
float vol;
|
||||
|
@ -203,8 +219,9 @@ alsa_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
|||
|
||||
err = snd_mixer_selem_set_playback_volume_all(am->elem, level);
|
||||
if (err < 0) {
|
||||
g_warning("problems setting alsa volume: %s\n",
|
||||
snd_strerror(err));
|
||||
g_set_error(error_r, alsa_mixer_quark(), err,
|
||||
"failed to set ALSA volume: %s",
|
||||
snd_strerror(err));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -49,6 +49,15 @@ struct oss_mixer {
|
|||
int volume_control;
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
oss_mixer_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("oss_mixer");
|
||||
}
|
||||
|
||||
static int
|
||||
oss_find_mixer(const char *name)
|
||||
{
|
||||
|
@ -65,7 +74,7 @@ oss_find_mixer(const char *name)
|
|||
}
|
||||
|
||||
static struct mixer *
|
||||
oss_mixer_init(const struct config_param *param)
|
||||
oss_mixer_init(const struct config_param *param, GError **error_r)
|
||||
{
|
||||
struct oss_mixer *om = g_new(struct oss_mixer, 1);
|
||||
|
||||
|
@ -78,9 +87,9 @@ oss_mixer_init(const struct config_param *param)
|
|||
if (om->control != NULL) {
|
||||
om->volume_control = oss_find_mixer(om->control);
|
||||
if (om->volume_control < 0) {
|
||||
g_warning("mixer control \"%s\" not found",
|
||||
om->control);
|
||||
g_free(om);
|
||||
g_set_error(error_r, oss_mixer_quark(), 0,
|
||||
"no such mixer control: %s", om->control);
|
||||
return NULL;
|
||||
}
|
||||
} else
|
||||
|
@ -108,13 +117,15 @@ oss_mixer_close(struct mixer *data)
|
|||
}
|
||||
|
||||
static bool
|
||||
oss_mixer_open(struct mixer *data)
|
||||
oss_mixer_open(struct mixer *data, GError **error_r)
|
||||
{
|
||||
struct oss_mixer *om = (struct oss_mixer *) data;
|
||||
|
||||
om->device_fd = open(om->device, O_RDONLY);
|
||||
if (om->device_fd < 0) {
|
||||
g_warning("Unable to open oss mixer \"%s\"\n", om->device);
|
||||
g_set_error(error_r, oss_mixer_quark(), errno,
|
||||
"failed to open %s: %s",
|
||||
om->device, g_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -122,14 +133,17 @@ oss_mixer_open(struct mixer *data)
|
|||
int devmask = 0;
|
||||
|
||||
if (ioctl(om->device_fd, SOUND_MIXER_READ_DEVMASK, &devmask) < 0) {
|
||||
g_warning("errors getting read_devmask for oss mixer\n");
|
||||
g_set_error(error_r, oss_mixer_quark(), errno,
|
||||
"READ_DEVMASK failed: %s",
|
||||
g_strerror(errno));
|
||||
oss_mixer_close(data);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (((1 << om->volume_control) & devmask) == 0) {
|
||||
g_warning("mixer control \"%s\" not usable\n",
|
||||
om->control);
|
||||
g_set_error(error_r, oss_mixer_quark(), 0,
|
||||
"mixer control \"%s\" not usable",
|
||||
om->control);
|
||||
oss_mixer_close(data);
|
||||
return false;
|
||||
}
|
||||
|
@ -138,7 +152,7 @@ oss_mixer_open(struct mixer *data)
|
|||
}
|
||||
|
||||
static int
|
||||
oss_mixer_get_volume(struct mixer *mixer)
|
||||
oss_mixer_get_volume(struct mixer *mixer, GError **error_r)
|
||||
{
|
||||
struct oss_mixer *om = (struct oss_mixer *)mixer;
|
||||
int left, right, level;
|
||||
|
@ -148,7 +162,9 @@ oss_mixer_get_volume(struct mixer *mixer)
|
|||
|
||||
ret = ioctl(om->device_fd, MIXER_READ(om->volume_control), &level);
|
||||
if (ret < 0) {
|
||||
g_warning("unable to read oss volume\n");
|
||||
g_set_error(error_r, oss_mixer_quark(), errno,
|
||||
"failed to read OSS volume: %s",
|
||||
g_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -164,7 +180,7 @@ oss_mixer_get_volume(struct mixer *mixer)
|
|||
}
|
||||
|
||||
static bool
|
||||
oss_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
||||
oss_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
|
||||
{
|
||||
struct oss_mixer *om = (struct oss_mixer *)mixer;
|
||||
int level;
|
||||
|
@ -177,7 +193,9 @@ oss_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
|||
|
||||
ret = ioctl(om->device_fd, MIXER_WRITE(om->volume_control), &level);
|
||||
if (ret < 0) {
|
||||
g_warning("unable to set oss volume\n");
|
||||
g_set_error(error_r, oss_mixer_quark(), errno,
|
||||
"failed to set OSS volume: %s",
|
||||
g_strerror(errno));
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,6 +45,15 @@ struct pulse_mixer {
|
|||
|
||||
};
|
||||
|
||||
/**
|
||||
* The quark used for GError.domain.
|
||||
*/
|
||||
static inline GQuark
|
||||
pulse_mixer_quark(void)
|
||||
{
|
||||
return g_quark_from_static_string("pulse_mixer");
|
||||
}
|
||||
|
||||
/**
|
||||
* \brief waits for a pulseaudio operation to finish, frees it and
|
||||
* unlocks the mainloop
|
||||
|
@ -203,7 +212,8 @@ context_state_cb(pa_context *context, void *userdata)
|
|||
|
||||
|
||||
static struct mixer *
|
||||
pulse_mixer_init(const struct config_param *param)
|
||||
pulse_mixer_init(const struct config_param *param,
|
||||
G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct pulse_mixer *pm = g_new(struct pulse_mixer,1);
|
||||
mixer_init(&pm->base, &pulse_mixer_plugin);
|
||||
|
@ -226,13 +236,14 @@ pulse_mixer_finish(struct mixer *data)
|
|||
}
|
||||
|
||||
static bool
|
||||
pulse_mixer_setup(struct pulse_mixer *pm)
|
||||
pulse_mixer_setup(struct pulse_mixer *pm, GError **error_r)
|
||||
{
|
||||
pa_context_set_state_callback(pm->context, context_state_cb, pm);
|
||||
|
||||
if (pa_context_connect(pm->context, pm->server,
|
||||
(pa_context_flags_t)0, NULL) < 0) {
|
||||
g_debug("context server fail");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"pa_context_connect() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -240,15 +251,18 @@ pulse_mixer_setup(struct pulse_mixer *pm)
|
|||
|
||||
if (pa_threaded_mainloop_start(pm->mainloop) < 0) {
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
g_debug("error start mainloop");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"pa_threaded_mainloop_start() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
pa_threaded_mainloop_wait(pm->mainloop);
|
||||
|
||||
if (pa_context_get_state(pm->context) != PA_CONTEXT_READY) {
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"failed to connect: %s",
|
||||
pa_strerror(pa_context_errno(pm->context)));
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
g_debug("error context not ready");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -258,7 +272,7 @@ pulse_mixer_setup(struct pulse_mixer *pm)
|
|||
}
|
||||
|
||||
static bool
|
||||
pulse_mixer_open(struct mixer *data)
|
||||
pulse_mixer_open(struct mixer *data, GError **error_r)
|
||||
{
|
||||
struct pulse_mixer *pm = (struct pulse_mixer *) data;
|
||||
|
||||
|
@ -269,7 +283,8 @@ pulse_mixer_open(struct mixer *data)
|
|||
|
||||
pm->mainloop = pa_threaded_mainloop_new();
|
||||
if (pm->mainloop == NULL) {
|
||||
g_debug("failed mainloop");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"pa_threaded_mainloop_new() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -278,11 +293,12 @@ pulse_mixer_open(struct mixer *data)
|
|||
if (pm->context == NULL) {
|
||||
pa_threaded_mainloop_stop(pm->mainloop);
|
||||
pa_threaded_mainloop_free(pm->mainloop);
|
||||
g_debug("failed context");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"pa_context_new() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pulse_mixer_setup(pm)) {
|
||||
if (!pulse_mixer_setup(pm, error_r)) {
|
||||
pa_threaded_mainloop_stop(pm->mainloop);
|
||||
pa_context_disconnect(pm->context);
|
||||
pa_context_unref(pm->context);
|
||||
|
@ -307,7 +323,7 @@ pulse_mixer_close(struct mixer *data)
|
|||
}
|
||||
|
||||
static int
|
||||
pulse_mixer_get_volume(struct mixer *mixer)
|
||||
pulse_mixer_get_volume(struct mixer *mixer, GError **error_r)
|
||||
{
|
||||
struct pulse_mixer *pm = (struct pulse_mixer *) mixer;
|
||||
int ret;
|
||||
|
@ -324,12 +340,15 @@ pulse_mixer_get_volume(struct mixer *mixer)
|
|||
sink_input_vol, pm);
|
||||
if (o == NULL) {
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
g_debug("pa_context_get_sink_input_info() failed");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"pa_context_get_sink_input_info() has failed");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!pulse_wait_for_operation(pm->mainloop, o)) {
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"failed to read PulseAudio volume");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -343,7 +362,7 @@ pulse_mixer_get_volume(struct mixer *mixer)
|
|||
}
|
||||
|
||||
static bool
|
||||
pulse_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
||||
pulse_mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
|
||||
{
|
||||
struct pulse_mixer *pm = (struct pulse_mixer *) mixer;
|
||||
struct pa_cvolume cvolume;
|
||||
|
@ -353,6 +372,7 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
|||
|
||||
if (!pm->online) {
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0, "disconnected");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -363,7 +383,8 @@ pulse_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
|||
&cvolume, NULL, NULL);
|
||||
pa_threaded_mainloop_unlock(pm->mainloop);
|
||||
if (o == NULL) {
|
||||
g_debug("pa_context_set_sink_input_volume() failed");
|
||||
g_set_error(error_r, pulse_mixer_quark(), 0,
|
||||
"failed to set PulseAudio volume");
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
|
@ -37,7 +37,8 @@ struct software_mixer {
|
|||
};
|
||||
|
||||
static struct mixer *
|
||||
software_mixer_init(G_GNUC_UNUSED const struct config_param *param)
|
||||
software_mixer_init(G_GNUC_UNUSED const struct config_param *param,
|
||||
G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct software_mixer *sm = g_new(struct software_mixer, 1);
|
||||
|
||||
|
@ -60,7 +61,7 @@ software_mixer_finish(struct mixer *data)
|
|||
}
|
||||
|
||||
static bool
|
||||
software_mixer_open(struct mixer *data)
|
||||
software_mixer_open(struct mixer *data, G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct software_mixer *sm = (struct software_mixer *)data;
|
||||
|
||||
|
@ -77,7 +78,7 @@ software_mixer_close(struct mixer *data)
|
|||
}
|
||||
|
||||
static int
|
||||
software_mixer_get_volume(struct mixer *mixer)
|
||||
software_mixer_get_volume(struct mixer *mixer, G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct software_mixer *sm = (struct software_mixer *)mixer;
|
||||
|
||||
|
@ -85,7 +86,8 @@ software_mixer_get_volume(struct mixer *mixer)
|
|||
}
|
||||
|
||||
static bool
|
||||
software_mixer_set_volume(struct mixer *mixer, unsigned volume)
|
||||
software_mixer_set_volume(struct mixer *mixer, unsigned volume,
|
||||
G_GNUC_UNUSED GError **error_r)
|
||||
{
|
||||
struct software_mixer *sm = (struct software_mixer *)mixer;
|
||||
|
||||
|
|
|
@ -38,6 +38,8 @@ output_mixer_get_volume(unsigned i)
|
|||
{
|
||||
struct audio_output *output;
|
||||
struct mixer *mixer;
|
||||
int volume;
|
||||
GError *error = NULL;
|
||||
|
||||
assert(i < audio_output_count());
|
||||
|
||||
|
@ -49,7 +51,14 @@ output_mixer_get_volume(unsigned i)
|
|||
if (mixer == NULL)
|
||||
return -1;
|
||||
|
||||
return mixer_get_volume(mixer);
|
||||
volume = mixer_get_volume(mixer, &error);
|
||||
if (volume < 0 && error != NULL) {
|
||||
g_warning("Failed to read mixer for '%s': %s",
|
||||
output->name, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
return volume;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -77,6 +86,8 @@ output_mixer_set_volume(unsigned i, unsigned volume)
|
|||
{
|
||||
struct audio_output *output;
|
||||
struct mixer *mixer;
|
||||
bool success;
|
||||
GError *error = NULL;
|
||||
|
||||
assert(i < audio_output_count());
|
||||
assert(volume <= 100);
|
||||
|
@ -89,7 +100,14 @@ output_mixer_set_volume(unsigned i, unsigned volume)
|
|||
if (mixer == NULL)
|
||||
return false;
|
||||
|
||||
return mixer_set_volume(mixer, volume);
|
||||
success = mixer_set_volume(mixer, volume, &error);
|
||||
if (!success && error != NULL) {
|
||||
g_warning("Failed to set mixer for '%s': %s",
|
||||
output->name, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -123,7 +141,7 @@ output_mixer_get_software_volume(unsigned i)
|
|||
if (mixer == NULL || mixer->plugin != &software_mixer_plugin)
|
||||
return -1;
|
||||
|
||||
return mixer_get_volume(mixer);
|
||||
return mixer_get_volume(mixer, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -157,6 +175,6 @@ mixer_all_set_software_volume(unsigned volume)
|
|||
struct audio_output *output = audio_output_get(i);
|
||||
if (output->mixer != NULL &&
|
||||
output->mixer->plugin == &software_mixer_plugin)
|
||||
mixer_set_volume(output->mixer, volume);
|
||||
mixer_set_volume(output->mixer, volume, NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,8 +20,6 @@
|
|||
#include "mixer_control.h"
|
||||
#include "mixer_api.h"
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <assert.h>
|
||||
#include <stddef.h>
|
||||
|
||||
|
@ -29,13 +27,14 @@
|
|||
#define G_LOG_DOMAIN "mixer"
|
||||
|
||||
struct mixer *
|
||||
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param)
|
||||
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param,
|
||||
GError **error_r)
|
||||
{
|
||||
struct mixer *mixer;
|
||||
|
||||
assert(plugin != NULL);
|
||||
|
||||
mixer = plugin->init(param);
|
||||
mixer = plugin->init(param, error_r);
|
||||
|
||||
assert(mixer == NULL || mixer->plugin == plugin);
|
||||
|
||||
|
@ -55,7 +54,7 @@ mixer_free(struct mixer *mixer)
|
|||
}
|
||||
|
||||
bool
|
||||
mixer_open(struct mixer *mixer)
|
||||
mixer_open(struct mixer *mixer, GError **error_r)
|
||||
{
|
||||
bool success;
|
||||
|
||||
|
@ -67,7 +66,7 @@ mixer_open(struct mixer *mixer)
|
|||
if (mixer->open)
|
||||
success = true;
|
||||
else
|
||||
success = mixer->open = mixer->plugin->open(mixer);
|
||||
success = mixer->open = mixer->plugin->open(mixer, error_r);
|
||||
|
||||
mixer->failed = !success;
|
||||
|
||||
|
@ -123,19 +122,20 @@ mixer_failed(struct mixer *mixer)
|
|||
}
|
||||
|
||||
int
|
||||
mixer_get_volume(struct mixer *mixer)
|
||||
mixer_get_volume(struct mixer *mixer, GError **error_r)
|
||||
{
|
||||
int volume;
|
||||
|
||||
assert(mixer != NULL);
|
||||
|
||||
if (mixer->plugin->global && !mixer->failed && !mixer_open(mixer))
|
||||
if (mixer->plugin->global && !mixer->failed &&
|
||||
!mixer_open(mixer, error_r))
|
||||
return -1;
|
||||
|
||||
g_mutex_lock(mixer->mutex);
|
||||
|
||||
if (mixer->open) {
|
||||
volume = mixer->plugin->get_volume(mixer);
|
||||
volume = mixer->plugin->get_volume(mixer, error_r);
|
||||
if (volume < 0)
|
||||
mixer_failed(mixer);
|
||||
} else
|
||||
|
@ -147,20 +147,21 @@ mixer_get_volume(struct mixer *mixer)
|
|||
}
|
||||
|
||||
bool
|
||||
mixer_set_volume(struct mixer *mixer, unsigned volume)
|
||||
mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r)
|
||||
{
|
||||
bool success;
|
||||
|
||||
assert(mixer != NULL);
|
||||
assert(volume <= 100);
|
||||
|
||||
if (mixer->plugin->global && !mixer->failed && !mixer_open(mixer))
|
||||
if (mixer->plugin->global && !mixer->failed &&
|
||||
!mixer_open(mixer, error_r))
|
||||
return false;
|
||||
|
||||
g_mutex_lock(mixer->mutex);
|
||||
|
||||
if (mixer->open) {
|
||||
success = mixer->plugin->set_volume(mixer, volume);
|
||||
success = mixer->plugin->set_volume(mixer, volume, error_r);
|
||||
if (!success)
|
||||
mixer_failed(mixer);
|
||||
} else
|
||||
|
|
|
@ -25,6 +25,8 @@
|
|||
#ifndef MPD_MIXER_CONTROL_H
|
||||
#define MPD_MIXER_CONTROL_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct mixer;
|
||||
|
@ -32,13 +34,14 @@ struct mixer_plugin;
|
|||
struct config_param;
|
||||
|
||||
struct mixer *
|
||||
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param);
|
||||
mixer_new(const struct mixer_plugin *plugin, const struct config_param *param,
|
||||
GError **error_r);
|
||||
|
||||
void
|
||||
mixer_free(struct mixer *mixer);
|
||||
|
||||
bool
|
||||
mixer_open(struct mixer *mixer);
|
||||
mixer_open(struct mixer *mixer, GError **error_r);
|
||||
|
||||
void
|
||||
mixer_close(struct mixer *mixer);
|
||||
|
@ -51,9 +54,9 @@ void
|
|||
mixer_auto_close(struct mixer *mixer);
|
||||
|
||||
int
|
||||
mixer_get_volume(struct mixer *mixer);
|
||||
mixer_get_volume(struct mixer *mixer, GError **error_r);
|
||||
|
||||
bool
|
||||
mixer_set_volume(struct mixer *mixer, unsigned volume);
|
||||
mixer_set_volume(struct mixer *mixer, unsigned volume, GError **error_r);
|
||||
|
||||
#endif
|
||||
|
|
|
@ -27,6 +27,8 @@
|
|||
#ifndef MPD_MIXER_PLUGIN_H
|
||||
#define MPD_MIXER_PLUGIN_H
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
struct config_param;
|
||||
|
@ -35,8 +37,13 @@ struct mixer;
|
|||
struct mixer_plugin {
|
||||
/**
|
||||
* Alocates and configures a mixer device.
|
||||
*
|
||||
* @param error_r location to store the error occuring, or
|
||||
* NULL to ignore errors
|
||||
* @return a mixer object, or NULL on error
|
||||
*/
|
||||
struct mixer *(*init)(const struct config_param *param);
|
||||
struct mixer *(*init)(const struct config_param *param,
|
||||
GError **error_r);
|
||||
|
||||
/**
|
||||
* Finish and free mixer data
|
||||
|
@ -45,8 +52,12 @@ struct mixer_plugin {
|
|||
|
||||
/**
|
||||
* Open mixer device
|
||||
*
|
||||
* @param error_r location to store the error occuring, or
|
||||
* NULL to ignore errors
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool (*open)(struct mixer *data);
|
||||
bool (*open)(struct mixer *data, GError **error_r);
|
||||
|
||||
/**
|
||||
* Close mixer device
|
||||
|
@ -56,18 +67,23 @@ struct mixer_plugin {
|
|||
/**
|
||||
* Reads the current volume.
|
||||
*
|
||||
* @param error_r location to store the error occuring, or
|
||||
* NULL to ignore errors
|
||||
* @return the current volume (0..100 including) or -1 on
|
||||
* error
|
||||
*/
|
||||
int (*get_volume)(struct mixer *mixer);
|
||||
int (*get_volume)(struct mixer *mixer, GError **error_r);
|
||||
|
||||
/**
|
||||
* Sets the volume.
|
||||
*
|
||||
* @param error_r location to store the error occuring, or
|
||||
* NULL to ignore errors
|
||||
* @param volume the new volume (0..100 including)
|
||||
* @return true on success
|
||||
* @return true on success, false on error
|
||||
*/
|
||||
bool (*set_volume)(struct mixer *mixer, unsigned volume);
|
||||
bool (*set_volume)(struct mixer *mixer, unsigned volume,
|
||||
GError **error_r);
|
||||
|
||||
/**
|
||||
* If true, then the mixer is automatically opened, even if
|
||||
|
|
|
@ -102,8 +102,15 @@ audio_output_open(struct audio_output *ao,
|
|||
ao_command(ao, ao->open ? AO_COMMAND_REOPEN : AO_COMMAND_OPEN);
|
||||
open = ao->open;
|
||||
|
||||
if (open && ao->mixer != NULL)
|
||||
mixer_open(ao->mixer);
|
||||
if (open && ao->mixer != NULL) {
|
||||
GError *error = NULL;
|
||||
|
||||
if (!mixer_open(ao->mixer, &error)) {
|
||||
g_warning("Failed to open mixer for '%s': %s",
|
||||
ao->name, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
}
|
||||
|
||||
return open;
|
||||
}
|
||||
|
|
|
@ -91,7 +91,8 @@ audio_output_mixer_type(const struct config_param *param)
|
|||
static struct mixer *
|
||||
audio_output_load_mixer(const struct config_param *param,
|
||||
const struct mixer_plugin *plugin,
|
||||
struct filter *filter_chain)
|
||||
struct filter *filter_chain,
|
||||
GError **error_r)
|
||||
{
|
||||
struct mixer *mixer;
|
||||
|
||||
|
@ -104,10 +105,10 @@ audio_output_load_mixer(const struct config_param *param,
|
|||
if (plugin == NULL)
|
||||
return NULL;
|
||||
|
||||
return mixer_new(plugin, param);
|
||||
return mixer_new(plugin, param, error_r);
|
||||
|
||||
case MIXER_TYPE_SOFTWARE:
|
||||
mixer = mixer_new(&software_mixer_plugin, NULL);
|
||||
mixer = mixer_new(&software_mixer_plugin, NULL, NULL);
|
||||
assert(mixer != NULL);
|
||||
|
||||
filter_chain_append(filter_chain,
|
||||
|
@ -124,6 +125,7 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
|
|||
GError **error_r)
|
||||
{
|
||||
const struct audio_output_plugin *plugin = NULL;
|
||||
GError *error = NULL;
|
||||
|
||||
if (param) {
|
||||
const char *p;
|
||||
|
@ -199,7 +201,12 @@ audio_output_init(struct audio_output *ao, const struct config_param *param,
|
|||
return false;
|
||||
|
||||
ao->mixer = audio_output_load_mixer(param, plugin->mixer_plugin,
|
||||
ao->filter);
|
||||
ao->filter, &error);
|
||||
if (ao->mixer == NULL && error != NULL) {
|
||||
g_warning("Failed to initialize hardware mixer for '%s': %s",
|
||||
ao->name, error->message);
|
||||
g_error_free(error);
|
||||
}
|
||||
|
||||
/* the "convert" filter must be the last one in the chain */
|
||||
|
||||
|
|
|
@ -46,6 +46,7 @@ pcm_volume(G_GNUC_UNUSED void *buffer, G_GNUC_UNUSED int length,
|
|||
|
||||
int main(int argc, G_GNUC_UNUSED char **argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
struct mixer *mixer;
|
||||
bool success;
|
||||
int volume;
|
||||
|
@ -57,27 +58,34 @@ int main(int argc, G_GNUC_UNUSED char **argv)
|
|||
|
||||
g_thread_init(NULL);
|
||||
|
||||
mixer = mixer_new(&alsa_mixer_plugin, NULL);
|
||||
mixer = mixer_new(&alsa_mixer_plugin, NULL, &error);
|
||||
if (mixer == NULL) {
|
||||
g_printerr("mixer_new() failed\n");
|
||||
g_printerr("mixer_new() failed: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
success = mixer_open(mixer);
|
||||
success = mixer_open(mixer, &error);
|
||||
if (!success) {
|
||||
mixer_free(mixer);
|
||||
g_printerr("failed to open the mixer\n");
|
||||
g_printerr("failed to open the mixer: %s\n", error->message);
|
||||
g_error_free(error);
|
||||
return 2;
|
||||
}
|
||||
|
||||
volume = mixer_get_volume(mixer);
|
||||
volume = mixer_get_volume(mixer, &error);
|
||||
mixer_close(mixer);
|
||||
mixer_free(mixer);
|
||||
|
||||
assert(volume >= -1 && volume <= 100);
|
||||
|
||||
if (volume < 0) {
|
||||
g_printerr("failed to read volume\n");
|
||||
if (error != NULL) {
|
||||
g_printerr("failed to read volume: %s\n",
|
||||
error->message);
|
||||
g_error_free(error);
|
||||
} else
|
||||
g_printerr("failed to read volume\n");
|
||||
return 2;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue