|
Packit Service |
cd2a00 |
/*-*- linux-c -*-*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
/*
|
|
Packit Service |
cd2a00 |
* ALSA <-> PulseAudio mixer control plugin
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* Copyright (c) 2006 by Pierre Ossman <ossman@cendio.se>
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This library is free software; you can redistribute it and/or modify
|
|
Packit Service |
cd2a00 |
* it under the terms of the GNU Lesser General Public License as
|
|
Packit Service |
cd2a00 |
* published by the Free Software Foundation; either version 2.1 of
|
|
Packit Service |
cd2a00 |
* the License, or (at your option) any later version.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
cd2a00 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
cd2a00 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
cd2a00 |
* GNU Lesser General Public License for more details.
|
|
Packit Service |
cd2a00 |
*
|
|
Packit Service |
cd2a00 |
* You should have received a copy of the GNU Lesser General Public
|
|
Packit Service |
cd2a00 |
* License along with this library; if not, write to the Free Software
|
|
Packit Service |
cd2a00 |
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
|
Packit Service |
cd2a00 |
*/
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include <sys/poll.h>
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include <alsa/asoundlib.h>
|
|
Packit Service |
cd2a00 |
#include <alsa/control_external.h>
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#include "pulse.h"
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
typedef struct snd_ctl_pulse {
|
|
Packit Service |
cd2a00 |
snd_ctl_ext_t ext;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_pulse_t *p;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
char *source;
|
|
Packit Service |
cd2a00 |
char *sink;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_cvolume sink_volume;
|
|
Packit Service |
cd2a00 |
pa_cvolume source_volume;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int sink_muted;
|
|
Packit Service |
cd2a00 |
int source_muted;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
int subscribed;
|
|
Packit Service |
cd2a00 |
int updated;
|
|
Packit Service |
cd2a00 |
} snd_ctl_pulse_t;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#define SOURCE_VOL_NAME "Capture Volume"
|
|
Packit Service |
cd2a00 |
#define SOURCE_MUTE_NAME "Capture Switch"
|
|
Packit Service |
cd2a00 |
#define SINK_VOL_NAME "Master Playback Volume"
|
|
Packit Service |
cd2a00 |
#define SINK_MUTE_NAME "Master Playback Switch"
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
#define UPDATE_SINK_VOL 0x01
|
|
Packit Service |
cd2a00 |
#define UPDATE_SINK_MUTE 0x02
|
|
Packit Service |
cd2a00 |
#define UPDATE_SOURCE_VOL 0x04
|
|
Packit Service |
cd2a00 |
#define UPDATE_SOURCE_MUTE 0x08
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void sink_info_cb(pa_context * c, const pa_sink_info * i,
|
|
Packit Service |
cd2a00 |
int is_last, void *userdata)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
|
|
Packit Service |
cd2a00 |
int changed = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (is_last) {
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_signal(ctl->p->mainloop, 0);
|
|
Packit Service |
cd2a00 |
return;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(i);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!!ctl->sink_muted != !!i->mute) {
|
|
Packit Service |
cd2a00 |
ctl->sink_muted = i->mute;
|
|
Packit Service |
cd2a00 |
ctl->updated |= UPDATE_SINK_MUTE;
|
|
Packit Service |
cd2a00 |
changed = 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!pa_cvolume_equal(&ctl->sink_volume, &i->volume)) {
|
|
Packit Service |
cd2a00 |
ctl->sink_volume = i->volume;
|
|
Packit Service |
cd2a00 |
ctl->updated |= UPDATE_SINK_VOL;
|
|
Packit Service |
cd2a00 |
changed = 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (changed)
|
|
Packit Service |
cd2a00 |
pulse_poll_activate(ctl->p);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void source_info_cb(pa_context * c, const pa_source_info * i,
|
|
Packit Service |
cd2a00 |
int is_last, void *userdata)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
|
|
Packit Service |
cd2a00 |
int changed = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (is_last) {
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_signal(ctl->p->mainloop, 0);
|
|
Packit Service |
cd2a00 |
return;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(i);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!!ctl->source_muted != !!i->mute) {
|
|
Packit Service |
cd2a00 |
ctl->source_muted = i->mute;
|
|
Packit Service |
cd2a00 |
ctl->updated |= UPDATE_SOURCE_MUTE;
|
|
Packit Service |
cd2a00 |
changed = 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!pa_cvolume_equal(&ctl->source_volume, &i->volume)) {
|
|
Packit Service |
cd2a00 |
ctl->source_volume = i->volume;
|
|
Packit Service |
cd2a00 |
ctl->updated |= UPDATE_SOURCE_VOL;
|
|
Packit Service |
cd2a00 |
changed = 1;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (changed)
|
|
Packit Service |
cd2a00 |
pulse_poll_activate(ctl->p);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void event_cb(pa_context * c, pa_subscription_event_type_t t,
|
|
Packit Service |
cd2a00 |
uint32_t index, void *userdata)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
|
|
Packit Service |
cd2a00 |
pa_operation *o;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop || !ctl->p->context)
|
|
Packit Service |
cd2a00 |
return;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
|
|
Packit Service |
cd2a00 |
sink_info_cb, ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (o)
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_get_source_info_by_name(ctl->p->context,
|
|
Packit Service |
cd2a00 |
ctl->source, source_info_cb,
|
|
Packit Service |
cd2a00 |
ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (o)
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_update_volume(snd_ctl_pulse_t * ctl)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
pa_operation *o;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_get_sink_info_by_name(ctl->p->context, ctl->sink,
|
|
Packit Service |
cd2a00 |
sink_info_cb, ctl);
|
|
Packit Service |
cd2a00 |
if (o) {
|
|
Packit Service |
cd2a00 |
err = pulse_wait_operation(ctl->p, o);
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
} else
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_get_source_info_by_name(ctl->p->context,
|
|
Packit Service |
cd2a00 |
ctl->source, source_info_cb,
|
|
Packit Service |
cd2a00 |
ctl);
|
|
Packit Service |
cd2a00 |
if (o) {
|
|
Packit Service |
cd2a00 |
err = pulse_wait_operation(ctl->p, o);
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
} else
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_elem_count(snd_ctl_ext_t * ext)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int count = 0, err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0) {
|
|
Packit Service |
cd2a00 |
count = err;
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->source)
|
|
Packit Service |
cd2a00 |
count += 2;
|
|
Packit Service |
cd2a00 |
if (ctl->sink)
|
|
Packit Service |
cd2a00 |
count += 2;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return count;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_elem_list(snd_ctl_ext_t * ext, unsigned int offset,
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_t * id)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->source) {
|
|
Packit Service |
cd2a00 |
if (offset == 0)
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_set_name(id, SOURCE_VOL_NAME);
|
|
Packit Service |
cd2a00 |
else if (offset == 1)
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_set_name(id, SOURCE_MUTE_NAME);
|
|
Packit Service |
cd2a00 |
} else
|
|
Packit Service |
cd2a00 |
offset += 2;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err >= 0) {
|
|
Packit Service |
cd2a00 |
if (offset == 2)
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_set_name(id, SINK_VOL_NAME);
|
|
Packit Service |
cd2a00 |
else if (offset == 3)
|
|
Packit Service |
cd2a00 |
snd_ctl_elem_id_set_name(id, SINK_MUTE_NAME);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static snd_ctl_ext_key_t pulse_find_elem(snd_ctl_ext_t * ext,
|
|
Packit Service |
cd2a00 |
const snd_ctl_elem_id_t * id)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
const char *name;
|
|
Packit Service |
cd2a00 |
unsigned int numid;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
numid = snd_ctl_elem_id_get_numid(id);
|
|
Packit Service |
cd2a00 |
if (numid > 0 && numid <= 4)
|
|
Packit Service |
cd2a00 |
return numid - 1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
name = snd_ctl_elem_id_get_name(id);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (strcmp(name, SOURCE_VOL_NAME) == 0)
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
if (strcmp(name, SOURCE_MUTE_NAME) == 0)
|
|
Packit Service |
cd2a00 |
return 1;
|
|
Packit Service |
cd2a00 |
if (strcmp(name, SINK_VOL_NAME) == 0)
|
|
Packit Service |
cd2a00 |
return 2;
|
|
Packit Service |
cd2a00 |
if (strcmp(name, SINK_MUTE_NAME) == 0)
|
|
Packit Service |
cd2a00 |
return 3;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return SND_CTL_EXT_KEY_NOT_FOUND;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_get_attribute(snd_ctl_ext_t * ext, snd_ctl_ext_key_t key,
|
|
Packit Service |
cd2a00 |
int *type, unsigned int *acc,
|
|
Packit Service |
cd2a00 |
unsigned int *count)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int err = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (key > 3)
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_update_volume(ctl);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (key & 1)
|
|
Packit Service |
cd2a00 |
*type = SND_CTL_ELEM_TYPE_BOOLEAN;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
*type = SND_CTL_ELEM_TYPE_INTEGER;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
*acc = SND_CTL_EXT_ACCESS_READWRITE;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (key == 0)
|
|
Packit Service |
cd2a00 |
*count = ctl->source_volume.channels;
|
|
Packit Service |
cd2a00 |
else if (key == 2)
|
|
Packit Service |
cd2a00 |
*count = ctl->sink_volume.channels;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
*count = 1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_get_integer_info(snd_ctl_ext_t * ext,
|
|
Packit Service |
cd2a00 |
snd_ctl_ext_key_t key, long *imin,
|
|
Packit Service |
cd2a00 |
long *imax, long *istep)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
*istep = 1;
|
|
Packit Service |
cd2a00 |
*imin = 0;
|
|
Packit Service |
cd2a00 |
*imax = PA_VOLUME_NORM;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_read_integer(snd_ctl_ext_t * ext, snd_ctl_ext_key_t key,
|
|
Packit Service |
cd2a00 |
long *value)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int err = 0, i;
|
|
Packit Service |
cd2a00 |
pa_cvolume *vol = NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_update_volume(ctl);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
switch (key) {
|
|
Packit Service |
cd2a00 |
case 0:
|
|
Packit Service |
cd2a00 |
vol = &ctl->source_volume;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 1:
|
|
Packit Service |
cd2a00 |
*value = !ctl->source_muted;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 2:
|
|
Packit Service |
cd2a00 |
vol = &ctl->sink_volume;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 3:
|
|
Packit Service |
cd2a00 |
*value = !ctl->sink_muted;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
err = -EINVAL;
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (vol) {
|
|
Packit Service |
cd2a00 |
for (i = 0; i < vol->channels; i++)
|
|
Packit Service |
cd2a00 |
value[i] = vol->values[i];
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_write_integer(snd_ctl_ext_t * ext, snd_ctl_ext_key_t key,
|
|
Packit Service |
cd2a00 |
long *value)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int err = 0, i;
|
|
Packit Service |
cd2a00 |
pa_operation *o;
|
|
Packit Service |
cd2a00 |
pa_cvolume *vol = NULL;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_update_volume(ctl);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
switch (key) {
|
|
Packit Service |
cd2a00 |
case 0:
|
|
Packit Service |
cd2a00 |
vol = &ctl->source_volume;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 1:
|
|
Packit Service |
cd2a00 |
if (!!ctl->source_muted == !*value)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
ctl->source_muted = !*value;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 2:
|
|
Packit Service |
cd2a00 |
vol = &ctl->sink_volume;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
case 3:
|
|
Packit Service |
cd2a00 |
if (!!ctl->sink_muted == !*value)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
ctl->sink_muted = !*value;
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
default:
|
|
Packit Service |
cd2a00 |
err = -EINVAL;
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (vol) {
|
|
Packit Service |
cd2a00 |
for (i = 0; i < vol->channels; i++)
|
|
Packit Service |
cd2a00 |
if (value[i] != vol->values[i])
|
|
Packit Service |
cd2a00 |
break;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (i == vol->channels)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
for (i = 0; i < vol->channels; i++)
|
|
Packit Service |
cd2a00 |
vol->values[i] = value[i];
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (key == 0)
|
|
Packit Service |
cd2a00 |
o = pa_context_set_source_volume_by_name(ctl->p->
|
|
Packit Service |
cd2a00 |
context,
|
|
Packit Service |
cd2a00 |
ctl->
|
|
Packit Service |
cd2a00 |
source,
|
|
Packit Service |
cd2a00 |
vol,
|
|
Packit Service |
cd2a00 |
pulse_context_success_cb,
|
|
Packit Service |
cd2a00 |
ctl->p);
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
o = pa_context_set_sink_volume_by_name(ctl->p->
|
|
Packit Service |
cd2a00 |
context,
|
|
Packit Service |
cd2a00 |
ctl->sink,
|
|
Packit Service |
cd2a00 |
vol,
|
|
Packit Service |
cd2a00 |
pulse_context_success_cb,
|
|
Packit Service |
cd2a00 |
ctl->p);
|
|
Packit Service |
cd2a00 |
} else {
|
|
Packit Service |
cd2a00 |
if (key == 1)
|
|
Packit Service |
cd2a00 |
o = pa_context_set_source_mute_by_name(ctl->p->
|
|
Packit Service |
cd2a00 |
context,
|
|
Packit Service |
cd2a00 |
ctl->source,
|
|
Packit Service |
cd2a00 |
ctl->
|
|
Packit Service |
cd2a00 |
source_muted,
|
|
Packit Service |
cd2a00 |
pulse_context_success_cb,
|
|
Packit Service |
cd2a00 |
ctl->p);
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
o = pa_context_set_sink_mute_by_name(ctl->p->
|
|
Packit Service |
cd2a00 |
context,
|
|
Packit Service |
cd2a00 |
ctl->sink,
|
|
Packit Service |
cd2a00 |
ctl->
|
|
Packit Service |
cd2a00 |
sink_muted,
|
|
Packit Service |
cd2a00 |
pulse_context_success_cb,
|
|
Packit Service |
cd2a00 |
ctl->p);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!o) {
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_wait_operation(ctl->p, o);
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = 1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void pulse_subscribe_events(snd_ctl_ext_t * ext, int subscribe)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ctl->subscribed = !!(subscribe & SND_CTL_EVENT_MASK_VALUE);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_read_event(snd_ctl_ext_t * ext, snd_ctl_elem_id_t * id,
|
|
Packit Service |
cd2a00 |
unsigned int *event_mask)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int offset;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->updated || !ctl->subscribed) {
|
|
Packit Service |
cd2a00 |
err = -EAGAIN;
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->source)
|
|
Packit Service |
cd2a00 |
offset = 2;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
offset = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->updated & UPDATE_SOURCE_VOL) {
|
|
Packit Service |
cd2a00 |
pulse_elem_list(ext, 0, id);
|
|
Packit Service |
cd2a00 |
ctl->updated &= ~UPDATE_SOURCE_VOL;
|
|
Packit Service |
cd2a00 |
} else if (ctl->updated & UPDATE_SOURCE_MUTE) {
|
|
Packit Service |
cd2a00 |
pulse_elem_list(ext, 1, id);
|
|
Packit Service |
cd2a00 |
ctl->updated &= ~UPDATE_SOURCE_MUTE;
|
|
Packit Service |
cd2a00 |
} else if (ctl->updated & UPDATE_SINK_VOL) {
|
|
Packit Service |
cd2a00 |
pulse_elem_list(ext, offset + 0, id);
|
|
Packit Service |
cd2a00 |
ctl->updated &= ~UPDATE_SINK_VOL;
|
|
Packit Service |
cd2a00 |
} else if (ctl->updated & UPDATE_SINK_MUTE) {
|
|
Packit Service |
cd2a00 |
pulse_elem_list(ext, offset + 1, id);
|
|
Packit Service |
cd2a00 |
ctl->updated &= ~UPDATE_SINK_MUTE;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
*event_mask = SND_CTL_EVENT_MASK_VALUE;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->updated)
|
|
Packit Service |
cd2a00 |
pulse_poll_deactivate(ctl->p);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = 1;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static int pulse_ctl_poll_revents(snd_ctl_ext_t * ext, struct pollfd *pfd,
|
|
Packit Service |
cd2a00 |
unsigned int nfds,
|
|
Packit Service |
cd2a00 |
unsigned short *revents)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->p || !ctl->p->mainloop)
|
|
Packit Service |
cd2a00 |
return -EBADFD;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_check_connection(ctl->p);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto finish;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->updated)
|
|
Packit Service |
cd2a00 |
*revents = POLLIN;
|
|
Packit Service |
cd2a00 |
else
|
|
Packit Service |
cd2a00 |
*revents = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
finish:
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void pulse_close(snd_ctl_ext_t * ext)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = ext->private_data;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (ctl->p)
|
|
Packit Service |
cd2a00 |
pulse_free(ctl->p);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
free(ctl->source);
|
|
Packit Service |
cd2a00 |
free(ctl->sink);
|
|
Packit Service |
cd2a00 |
free(ctl);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static const snd_ctl_ext_callback_t pulse_ext_callback = {
|
|
Packit Service |
cd2a00 |
.elem_count = pulse_elem_count,
|
|
Packit Service |
cd2a00 |
.elem_list = pulse_elem_list,
|
|
Packit Service |
cd2a00 |
.find_elem = pulse_find_elem,
|
|
Packit Service |
cd2a00 |
.get_attribute = pulse_get_attribute,
|
|
Packit Service |
cd2a00 |
.get_integer_info = pulse_get_integer_info,
|
|
Packit Service |
cd2a00 |
.read_integer = pulse_read_integer,
|
|
Packit Service |
cd2a00 |
.write_integer = pulse_write_integer,
|
|
Packit Service |
cd2a00 |
.subscribe_events = pulse_subscribe_events,
|
|
Packit Service |
cd2a00 |
.read_event = pulse_read_event,
|
|
Packit Service |
cd2a00 |
.poll_revents = pulse_ctl_poll_revents,
|
|
Packit Service |
cd2a00 |
.close = pulse_close,
|
|
Packit Service |
cd2a00 |
};
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
static void server_info_cb(pa_context * c, const pa_server_info * i,
|
|
Packit Service |
cd2a00 |
void *userdata)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl = (snd_ctl_pulse_t *) userdata;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
assert(ctl && i);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (i->default_source_name && !ctl->source)
|
|
Packit Service |
cd2a00 |
ctl->source = strdup(i->default_source_name);
|
|
Packit Service |
cd2a00 |
if (i->default_sink_name && !ctl->sink)
|
|
Packit Service |
cd2a00 |
ctl->sink = strdup(i->default_sink_name);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_signal(ctl->p->mainloop, 0);
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
SND_CTL_PLUGIN_DEFINE_FUNC(pulse)
|
|
Packit Service |
cd2a00 |
{
|
|
Packit Service |
cd2a00 |
snd_config_iterator_t i, next;
|
|
Packit Service |
cd2a00 |
const char *server = NULL;
|
|
Packit Service |
cd2a00 |
const char *device = NULL;
|
|
Packit Service |
cd2a00 |
const char *source = NULL;
|
|
Packit Service |
cd2a00 |
const char *sink = NULL;
|
|
Packit Service |
cd2a00 |
const char *fallback_name = NULL;
|
|
Packit Service |
cd2a00 |
int err;
|
|
Packit Service |
cd2a00 |
snd_ctl_pulse_t *ctl;
|
|
Packit Service |
cd2a00 |
pa_operation *o;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
snd_config_for_each(i, next, conf) {
|
|
Packit Service |
cd2a00 |
snd_config_t *n = snd_config_iterator_entry(i);
|
|
Packit Service |
cd2a00 |
const char *id;
|
|
Packit Service |
cd2a00 |
if (snd_config_get_id(n, &id) < 0)
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0
|
|
Packit Service |
cd2a00 |
|| strcmp(id, "hint") == 0)
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "server") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &server) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "device") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &device) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "source") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &source) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "sink") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &sink) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid type for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
if (strcmp(id, "fallback") == 0) {
|
|
Packit Service |
cd2a00 |
if (snd_config_get_string(n, &fallback_name) < 0) {
|
|
Packit Service |
cd2a00 |
SNDERR("Invalid value for %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
continue;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
SNDERR("Unknown field %s", id);
|
|
Packit Service |
cd2a00 |
return -EINVAL;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (fallback_name && name && !strcmp(name, fallback_name))
|
|
Packit Service |
cd2a00 |
fallback_name = NULL; /* no fallback for the same name */
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ctl = calloc(1, sizeof(*ctl));
|
|
Packit Service |
cd2a00 |
if (!ctl)
|
|
Packit Service |
cd2a00 |
return -ENOMEM;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ctl->p = pulse_new();
|
|
Packit Service |
cd2a00 |
if (!ctl->p) {
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = pulse_connect(ctl->p, server, fallback_name != NULL);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (source)
|
|
Packit Service |
cd2a00 |
ctl->source = strdup(source);
|
|
Packit Service |
cd2a00 |
else if (device)
|
|
Packit Service |
cd2a00 |
ctl->source = strdup(device);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((source || device) && !ctl->source) {
|
|
Packit Service |
cd2a00 |
err = -ENOMEM;
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (sink)
|
|
Packit Service |
cd2a00 |
ctl->sink = strdup(sink);
|
|
Packit Service |
cd2a00 |
else if (device)
|
|
Packit Service |
cd2a00 |
ctl->sink = strdup(device);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if ((sink || device) && !ctl->sink) {
|
|
Packit Service |
cd2a00 |
err = -ENOMEM;
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (!ctl->source || !ctl->sink) {
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_get_server_info(ctl->p->context,
|
|
Packit Service |
cd2a00 |
server_info_cb, ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (o) {
|
|
Packit Service |
cd2a00 |
err = pulse_wait_operation(ctl->p, o);
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
} else
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_lock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_context_set_subscribe_callback(ctl->p->context, event_cb, ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
o = pa_context_subscribe(ctl->p->context,
|
|
Packit Service |
cd2a00 |
PA_SUBSCRIPTION_MASK_SINK |
|
|
Packit Service |
cd2a00 |
PA_SUBSCRIPTION_MASK_SOURCE,
|
|
Packit Service |
cd2a00 |
pulse_context_success_cb, ctl->p);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (o) {
|
|
Packit Service |
cd2a00 |
err = pulse_wait_operation(ctl->p, o);
|
|
Packit Service |
cd2a00 |
pa_operation_unref(o);
|
|
Packit Service |
cd2a00 |
} else
|
|
Packit Service |
cd2a00 |
err = -EIO;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
pa_threaded_mainloop_unlock(ctl->p->mainloop);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ctl->ext.version = SND_CTL_EXT_VERSION;
|
|
Packit Service |
cd2a00 |
ctl->ext.card_idx = 0;
|
|
Packit Service |
cd2a00 |
strncpy(ctl->ext.id, "pulse", sizeof(ctl->ext.id) - 1);
|
|
Packit Service |
cd2a00 |
strncpy(ctl->ext.driver, "PulseAudio plugin",
|
|
Packit Service |
cd2a00 |
sizeof(ctl->ext.driver) - 1);
|
|
Packit Service |
cd2a00 |
strncpy(ctl->ext.name, "PulseAudio", sizeof(ctl->ext.name) - 1);
|
|
Packit Service |
cd2a00 |
strncpy(ctl->ext.longname, "PulseAudio",
|
|
Packit Service |
cd2a00 |
sizeof(ctl->ext.longname) - 1);
|
|
Packit Service |
cd2a00 |
strncpy(ctl->ext.mixername, "PulseAudio",
|
|
Packit Service |
cd2a00 |
sizeof(ctl->ext.mixername) - 1);
|
|
Packit Service |
cd2a00 |
ctl->ext.poll_fd = ctl->p->main_fd;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
ctl->ext.callback = &pulse_ext_callback;
|
|
Packit Service |
cd2a00 |
ctl->ext.private_data = ctl;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
err = snd_ctl_ext_create(&ctl->ext, name, mode);
|
|
Packit Service |
cd2a00 |
if (err < 0)
|
|
Packit Service |
cd2a00 |
goto error;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
*handlep = ctl->ext.handle;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return 0;
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
error:
|
|
Packit Service |
cd2a00 |
if (ctl->p)
|
|
Packit Service |
cd2a00 |
pulse_free(ctl->p);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
free(ctl->source);
|
|
Packit Service |
cd2a00 |
free(ctl->sink);
|
|
Packit Service |
cd2a00 |
free(ctl);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
if (fallback_name)
|
|
Packit Service |
cd2a00 |
return snd_ctl_open_fallback(handlep, root,
|
|
Packit Service |
cd2a00 |
fallback_name, name, mode);
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
return err;
|
|
Packit Service |
cd2a00 |
}
|
|
Packit Service |
cd2a00 |
|
|
Packit Service |
cd2a00 |
SND_CTL_PLUGIN_SYMBOL(pulse);
|