lots of new pulse features:

*all sink operations now work on sources
*sources are now available for finding/watching
*ports are available
*active port is settable


SVN revision: 64513
This commit is contained in:
Mike Blumenkrantz 2011-10-29 22:45:50 +00:00
parent db88f8f57d
commit 987bccb984
6 changed files with 199 additions and 45 deletions

View File

@ -12,8 +12,15 @@ extern int PULSE_EVENT_CHANGE;
typedef struct Pulse Pulse;
typedef uint32_t Pulse_Tag_Id;
typedef struct Pulse_Sink Pulse_Sink;
typedef struct Pulse_Sink Pulse_Source;
typedef void (*Pulse_Cb)(Pulse *, Pulse_Tag_Id, void *);
typedef struct Pulse_Sink_Port_Info {
const char *name; /**< Name of this port */
const char *description; /**< Description of this port */
uint32_t priority; /**< The higher this value is the more useful this port is as a default */
} Pulse_Sink_Port_Info;
int pulse_init(void);
void pulse_shutdown(void);
@ -23,9 +30,18 @@ void pulse_free(Pulse *conn);
void pulse_cb_set(Pulse *conn, uint32_t tagnum, Pulse_Cb cb);
uint32_t pulse_cards_get(Pulse *conn);
uint32_t pulse_sinks_get(Pulse *conn);
uint32_t pulse_sink_get(Pulse *conn, uint32_t idx);
uint32_t pulse_sink_mute_set(Pulse *conn, uint32_t idx, Eina_Bool mute);
#define pulse_sinks_get(conn) pulse_types_get((conn), EINA_FALSE)
#define pulse_sources_get(conn) pulse_types_get((conn), EINA_TRUE)
uint32_t pulse_types_get(Pulse *conn, Eina_Bool source);
#define pulse_sink_get(conn, idx) pulse_type_get((conn), (idx), EINA_FALSE)
#define pulse_source_get(conn, idx) pulse_type_get((conn), (idx), EINA_FALSE)
uint32_t pulse_type_get(Pulse *conn, uint32_t idx, Eina_Bool source);
#define pulse_sink_mute_set(conn, idx, mute) pulse_type_mute_set((conn), (idx), (mute), EINA_FALSE)
#define pulse_source_mute_set(conn, idx, mute) pulse_type_mute_set((conn), (idx), (mute), EINA_TRUE)
uint32_t pulse_type_mute_set(Pulse *conn, uint32_t idx, Eina_Bool mute, Eina_Bool source);
#define pulse_sink_volume_set(conn, idx, channels, vol) pulse_type_volume_set((conn), (idx), (channels), (vol), EINA_FALSE)
#define pulse_source_volume_set(conn, idx, channels, vol) pulse_type_volume_set((conn), (idx), (channels), (vol), EINA_TRUE)
uint32_t pulse_type_volume_set(Pulse *conn, uint32_t sink_num, uint8_t channels, double vol, Eina_Bool source);
void pulse_sink_free(Pulse_Sink *sink);
const char *pulse_sink_name_get(Pulse_Sink *sink);
@ -38,7 +54,11 @@ uint8_t pulse_sink_channels_count(Pulse_Sink *sink);
Eina_List *pulse_sink_channel_names_get(Pulse_Sink *sink);
Eina_Bool pulse_sinks_watch(Pulse *conn);
const Eina_List *pulse_sink_ports_get(Pulse_Sink *sink);
const char *pulse_sink_port_active_get(Pulse_Sink *sink);
#define pulse_source_channel_volume_set pulse_sink_channel_volume_set
uint32_t pulse_sink_channel_volume_set(Pulse *conn, Pulse_Sink *sink, uint32_t id, double vol);
uint32_t pulse_sink_port_set(Pulse *conn, Pulse_Sink *sink, const char *port);
double pulse_sink_channel_volume_get(Pulse_Sink *sink, unsigned int id);
float pulse_sink_channel_balance_get(Pulse_Sink *sink, unsigned int id);
float pulse_sink_channel_depth_get(Pulse_Sink *sink, unsigned int id);

View File

@ -15,6 +15,7 @@ int PULSE_EVENT_CONNECTED = -1;
int PULSE_EVENT_DISCONNECTED = -1;
int PULSE_EVENT_CHANGE = -1;
Eina_Hash *pulse_sinks = NULL;
Eina_Hash *pulse_sources = NULL;
void
pulse_fake_free(void *d __UNUSED__, void *d2 __UNUSED__)
@ -390,11 +391,11 @@ pulse_cb_set(Pulse *conn, uint32_t tagnum, Pulse_Cb cb)
}
uint32_t
pulse_sink_get(Pulse *conn, uint32_t sink_num)
pulse_type_get(Pulse *conn, uint32_t idx, Eina_Bool source)
{
Pulse_Tag *tag;
int read;
uint32_t type = PA_COMMAND_GET_SINK_INFO;
uint32_t type = source ? PA_COMMAND_GET_SOURCE_INFO : PA_COMMAND_GET_SINK_INFO;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
tag = calloc(1, sizeof(Pulse_Tag));
@ -403,7 +404,7 @@ pulse_sink_get(Pulse *conn, uint32_t sink_num)
tag->data = malloc(tag->dsize);
tag->tag_count = conn->tag_count;
tag_simple_init(conn, tag, type, PA_TAG_U32);
tag_uint32(tag, sink_num);
tag_uint32(tag, idx);
tag_string(tag, NULL);
tag_finish(tag);
read = !!ecore_main_fd_handler_active_get(conn->fdh, ECORE_FD_READ) * ECORE_FD_READ;
@ -414,11 +415,11 @@ pulse_sink_get(Pulse *conn, uint32_t sink_num)
}
uint32_t
pulse_sinks_get(Pulse *conn)
pulse_types_get(Pulse *conn, Eina_Bool source)
{
Pulse_Tag *tag;
int read;
uint32_t type = PA_COMMAND_GET_SINK_INFO_LIST;
uint32_t type = source ? PA_COMMAND_GET_SOURCE_INFO_LIST : PA_COMMAND_GET_SINK_INFO_LIST;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
tag = calloc(1, sizeof(Pulse_Tag));
@ -436,11 +437,12 @@ pulse_sinks_get(Pulse *conn)
}
uint32_t
pulse_sink_mute_set(Pulse *conn, uint32_t sink_num, Eina_Bool mute)
pulse_type_mute_set(Pulse *conn, uint32_t sink_num, Eina_Bool mute, Eina_Bool source)
{
Pulse_Tag *tag;
int read;
uint32_t type = PA_COMMAND_SET_SINK_MUTE;
uint32_t type = source ? PA_COMMAND_SET_SOURCE_MUTE : PA_COMMAND_SET_SINK_MUTE;
Eina_Hash *h;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
tag = calloc(1, sizeof(Pulse_Tag));
@ -457,22 +459,23 @@ pulse_sink_mute_set(Pulse *conn, uint32_t sink_num, Eina_Bool mute)
ecore_main_fd_handler_active_set(conn->fdh, read | ECORE_FD_WRITE);
conn->oq = eina_list_append(conn->oq, tag);
eina_hash_add(conn->tag_handlers, &tag->tag_count, (uintptr_t*)((uintptr_t)type));
if (pulse_sinks)
h = (source == EINA_TRUE) ? pulse_sources : pulse_sinks;
if (h)
{
Pulse_Sink *sink;
sink = eina_hash_find(pulse_sinks, &sink_num);
sink = eina_hash_find(h, &sink_num);
if (sink) sink->mute = !!mute;
}
return tag->tag_count;
}
uint32_t
pulse_sink_volume_set(Pulse *conn, uint32_t sink_num, uint8_t channels, double vol)
pulse_type_volume_set(Pulse *conn, uint32_t sink_num, uint8_t channels, double vol, Eina_Bool source)
{
Pulse_Tag *tag;
int read;
uint32_t type = PA_COMMAND_SET_SINK_VOLUME;
uint32_t type = source ? PA_COMMAND_SET_SOURCE_MUTE : PA_COMMAND_SET_SINK_VOLUME;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
tag = calloc(1, sizeof(Pulse_Tag));
@ -497,12 +500,13 @@ pulse_sink_channel_volume_set(Pulse *conn, Pulse_Sink *sink, uint32_t id, double
{
Pulse_Tag *tag;
int read;
uint32_t type = PA_COMMAND_SET_SINK_VOLUME;
uint32_t type;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
EINA_SAFETY_ON_TRUE_RETURN_VAL(id >= sink->channel_map.channels, 0);
tag = calloc(1, sizeof(Pulse_Tag));
EINA_SAFETY_ON_NULL_RETURN_VAL(tag, 0);
type = sink->source ? PA_COMMAND_SET_SOURCE_VOLUME : PA_COMMAND_SET_SINK_VOLUME;
tag->dsize = 3 * PA_TAG_SIZE_U32 + PA_TAG_SIZE_STRING_NULL + PA_TAG_SIZE_CVOLUME + sink->channel_map.channels * sizeof(uint32_t);
tag->data = malloc(tag->dsize);
tag->tag_count = conn->tag_count;
@ -520,6 +524,42 @@ pulse_sink_channel_volume_set(Pulse *conn, Pulse_Sink *sink, uint32_t id, double
return tag->tag_count;
}
uint32_t
pulse_sink_port_set(Pulse *conn, Pulse_Sink *sink, const char *port)
{
Pulse_Tag *tag;
int read;
uint32_t type;
Eina_List *l;
const char *p;
Eina_Bool match = EINA_FALSE;
EINA_SAFETY_ON_NULL_RETURN_VAL(conn, 0);
EINA_SAFETY_ON_NULL_RETURN_VAL(port, 0);
EINA_LIST_FOREACH(sink->ports, l, p)
{
match = !strcmp(p, port);
if (match) break;
}
EINA_SAFETY_ON_TRUE_RETURN_VAL(!match, 0);
tag = calloc(1, sizeof(Pulse_Tag));
EINA_SAFETY_ON_NULL_RETURN_VAL(tag, 0);
type = sink->source ? PA_COMMAND_SET_SOURCE_PORT : PA_COMMAND_SET_SINK_PORT;
tag->dsize = PA_TAG_SIZE_U32 + 2 * PA_TAG_SIZE_STRING + strlen(sink->name) + strlen(port);
tag->data = malloc(tag->dsize);
tag->tag_count = conn->tag_count;
tag_simple_init(conn, tag, type, PA_TAG_U32);
tag_uint32(tag, sink->index);
tag_string(tag, sink->name);
tag_string(tag, port);
tag_finish(tag);
read = !!ecore_main_fd_handler_active_get(conn->fdh, ECORE_FD_READ) * ECORE_FD_READ;
ecore_main_fd_handler_active_set(conn->fdh, read | ECORE_FD_WRITE);
conn->oq = eina_list_append(conn->oq, tag);
eina_hash_add(conn->tag_handlers, &tag->tag_count, (uintptr_t*)((uintptr_t)type));
return tag->tag_count;
}
Eina_Bool
pulse_sinks_watch(Pulse *conn)
{
@ -563,6 +603,9 @@ pulse_shutdown(void)
{
if ((!pulse_init_count) || (!--pulse_init_count)) return;
if (pulse_sinks) eina_hash_free(pulse_sinks);
if (pulse_sources) eina_hash_free(pulse_sources);
pulse_sinks = pulse_sources = NULL;
eina_log_domain_unregister(pa_log_dom);
ecore_con_shutdown();
ecore_shutdown();

View File

@ -432,12 +432,6 @@ typedef struct pa_cvolume {
pa_volume_t values[PA_CHANNELS_MAX]; /**< Per-channel volume */
} pa_cvolume;
typedef struct pa_sink_port_info {
const char *name; /**< Name of this port */
const char *description; /**< Description of this port */
uint32_t priority; /**< The higher this value is the more useful this port is as a default */
} pa_sink_port_info;
typedef struct pa_channel_map {
uint8_t channels;
/**< Number of channels */
@ -460,8 +454,11 @@ struct Pulse_Sink {
pa_channel_map channel_map; /**< Channel map */
// uint32_t owner_module; /**< Index of the owning module of this sink, or PA_INVALID_INDEX */
pa_cvolume volume; /**< Volume of the sink */
Eina_List *ports; /**< output ports */
const char *active_port; /**< currently active port */
Eina_Bool mute : 1; /**< Mute switch of the sink */
Eina_Bool update : 1;
Eina_Bool source : 1; /**< sink is actually a source */
};
typedef uint32_t pa_pstream_descriptor[PA_PSTREAM_DESCRIPTOR_MAX];
@ -537,5 +534,6 @@ void msg_send_creds(Pulse *conn, Pulse_Tag *tag);
Eina_Bool msg_send(Pulse *conn, Pulse_Tag *tag);
extern Eina_Hash *pulse_sinks;
extern Eina_Hash *pulse_sources;
#endif

View File

@ -14,25 +14,34 @@ deserialize_sinks_watcher(Pulse *conn, Pulse_Tag *tag)
Pulse_Sink *sink;
sink = eina_hash_find(pulse_sinks, &idx);
if (!sink) return;
if (pulse_sink_get(conn, idx))
sink->update = EINA_TRUE;
if (sink)
{
if (pulse_sink_get(conn, idx))
sink->update = EINA_TRUE;
}
else
{
sink = eina_hash_find(pulse_sources, &idx);
if (!sink) return;
if (pulse_source_get(conn, idx))
sink->update = EINA_TRUE;
}
}
}
Pulse_Sink *
deserialize_sink(Pulse *conn __UNUSED__, Pulse_Tag *tag)
static Pulse_Sink *
deserialize_sink(Pulse *conn __UNUSED__, Pulse_Tag *tag, Eina_Bool source)
{
Pulse_Sink *sink = NULL;
Eina_Bool mute, exist;
pa_sample_spec spec;
uint32_t owner_module, monitor_source, flags, base_volume, state, n_volume_steps, card, n_ports;
uint64_t latency, configured_latency;
const char *monitor_source_name, *driver, *active_port;
const char *monitor_source_name, *driver;
Eina_Hash *props;
unsigned int x;
monitor_source_name = driver = active_port = NULL;
monitor_source_name = driver = NULL;
EINA_SAFETY_ON_FALSE_GOTO(untag_uint32(tag, &x), error);
sink = eina_hash_find(pulse_sinks, &x);
exist = !!sink;
@ -63,21 +72,26 @@ deserialize_sink(Pulse *conn __UNUSED__, Pulse_Tag *tag)
for (x = 0; x < n_ports; x++)
{
pa_sink_port_info pi = {NULL, NULL, 0};
Pulse_Sink_Port_Info *pi;
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &pi.name), error);
eina_stringshare_del(pi.name);
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &pi.description), error);
eina_stringshare_del(pi.description);
EINA_SAFETY_ON_FALSE_GOTO(untag_uint32(tag, &pi.priority), error);
pi = calloc(1, sizeof(Pulse_Sink_Port_Info));
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &pi->name), error);
eina_stringshare_del(pi->name);
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &pi->description), error);
eina_stringshare_del(pi->description);
EINA_SAFETY_ON_FALSE_GOTO(untag_uint32(tag, &pi->priority), error);
sink->ports = eina_list_append(sink->ports, pi);
}
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &active_port), error);
EINA_SAFETY_ON_FALSE_GOTO(untag_string(tag, &sink->active_port), error);
if (exist)
ecore_event_add(PULSE_EVENT_CHANGE, sink, pulse_fake_free, NULL);
else
{
if (!pulse_sinks) pulse_sinks = eina_hash_int32_new(NULL);
eina_hash_add(pulse_sinks, (uintptr_t*)&sink->index, sink);
if (source && (!pulse_sources))
pulse_sources = eina_hash_int32_new((Eina_Free_Cb)pulse_sink_free);
else if ((!source) && (!pulse_sinks))
pulse_sinks = eina_hash_int32_new((Eina_Free_Cb)pulse_sink_free);
eina_hash_add(source ? pulse_sources : pulse_sinks, (uintptr_t*)&sink->index, sink);
}
return sink;
error:
@ -97,13 +111,14 @@ deserialize_tag(Pulse *conn, PA_Commands command, Pulse_Tag *tag)
switch (command)
{
case PA_COMMAND_GET_SINK_INFO_LIST:
case PA_COMMAND_GET_SOURCE_INFO_LIST:
if (!cb) return EINA_TRUE;
ev = NULL;
while (tag->size < tag->dsize - PA_TAG_SIZE_STRING_NULL)
{
Pulse_Sink *sink;
sink = deserialize_sink(conn, tag);
sink = deserialize_sink(conn, tag, (command == PA_COMMAND_GET_SOURCE_INFO_LIST));
if (!sink)
{
EINA_LIST_FREE(ev, sink)
@ -114,8 +129,9 @@ deserialize_tag(Pulse *conn, PA_Commands command, Pulse_Tag *tag)
}
break;
case PA_COMMAND_GET_SINK_INFO:
case PA_COMMAND_GET_SOURCE_INFO:
if ((!cb) && (!conn->watching)) return EINA_TRUE;
ev = deserialize_sink(conn, tag);
ev = deserialize_sink(conn, tag, (command == PA_COMMAND_GET_SOURCE_INFO));
break;
case 0:
deserialize_sinks_watcher(conn, tag);

View File

@ -150,16 +150,52 @@ static Eina_Bool on_rear(pa_channel_position_t p) {
return !!(PA_CHANNEL_POSITION_MASK(p) & PA_CHANNEL_POSITION_MASK_REAR);
}
static void
pulse_sink_port_info_free(Pulse_Sink_Port_Info *pi)
{
if (!pi) return;
eina_stringshare_del(pi->name);
eina_stringshare_del(pi->description);
free(pi);
}
void
pulse_sink_free(Pulse_Sink *sink)
{
Pulse_Sink_Port_Info *pi;
if (!sink) return;
if (sink->source)
{
if (eina_hash_del_by_key(pulse_sources, (uintptr_t*)&sink->index))
return;
}
else
{
if (eina_hash_del_by_key(pulse_sinks, (uintptr_t*)&sink->index))
return;
}
eina_stringshare_del(sink->name);
eina_stringshare_del(sink->description);
eina_hash_del_by_key(pulse_sinks, (uintptr_t*)&sink->index);
EINA_LIST_FREE(sink->ports, pi)
pulse_sink_port_info_free(pi);
eina_stringshare_del(sink->active_port);
free(sink);
}
const Eina_List *
pulse_sink_ports_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->ports;
}
const char *
pulse_sink_port_active_get(Pulse_Sink *sink)
{
EINA_SAFETY_ON_NULL_RETURN_VAL(sink, NULL);
return sink->active_port;
}
const char *
pulse_sink_name_get(Pulse_Sink *sink)
{

View File

@ -17,6 +17,7 @@ static Ecore_Event_Handler *ph = NULL;
static Ecore_Event_Handler *pch = NULL;
static Ecore_Event_Handler *pdh = NULL;
static Eina_List *sinks = NULL;
static Eina_List *sources = NULL;
static E_DBus_Connection *dbus = NULL;
static E_DBus_Signal_Handler *dbus_handler = NULL;
@ -105,6 +106,25 @@ _pulse_sinks_get(Pulse *p __UNUSED__, Pulse_Tag_Id id __UNUSED__, Eina_List *ev)
e_mod_mixer_pulse_ready(EINA_TRUE);
}
static void
_pulse_sources_get(Pulse *p __UNUSED__, Pulse_Tag_Id id __UNUSED__, Eina_List *ev)
{
Eina_List *l;
Pulse_Sink *sink;
sources = ev;
EINA_LIST_FOREACH(ev, l, sink)
{
printf("Sink:\n");
printf("\tname: %s\n", pulse_sink_name_get(sink));
printf("\tidx: %"PRIu32"\n", pulse_sink_idx_get(sink));
printf("\tdesc: %s\n", pulse_sink_desc_get(sink));
printf("\tchannels: %u\n", pulse_sink_channels_count(sink));
printf("\tmuted: %s\n", pulse_sink_muted_get(sink) ? "yes" : "no");
printf("\tavg: %g\n", pulse_sink_avg_get_pct(sink));
printf("\tbalance: %f\n", pulse_sink_balance_get(sink));
}
}
static Eina_Bool
_pulse_connected(Pulse *d, int type __UNUSED__, Pulse *ev)
{
@ -118,6 +138,9 @@ _pulse_connected(Pulse *d, int type __UNUSED__, Pulse *ev)
return ECORE_CALLBACK_RENEW;
}
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_sinks_get);
id = pulse_sources_get(conn);
if (id)
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_sources_get);
return ECORE_CALLBACK_RENEW;
}
@ -130,6 +153,8 @@ _pulse_disconnected(Pulse *d, int type __UNUSED__, Pulse *ev)
EINA_LIST_FREE(sinks, sink)
pulse_sink_free(sink);
EINA_LIST_FREE(sources, sink)
pulse_sink_free(sink);
if (last_disc && (ecore_time_unix_get() - last_disc < 1))
{
@ -158,6 +183,14 @@ _pulse_sink_find(const char *name)
if ((sink_name == name) || (!strcmp(sink_name, name)))
return sink;
}
EINA_LIST_FOREACH(sources, l, sink)
{
const char *sink_name;
sink_name = pulse_sink_name_get(sink);
if ((sink_name == name) || (!strcmp(sink_name, name)))
return sink;
}
return NULL;
}
@ -223,6 +256,8 @@ e_mixer_pulse_shutdown(void)
Pulse_Sink *sink;
EINA_LIST_FREE(sinks, sink)
pulse_sink_free(sink);
EINA_LIST_FREE(sources, sink)
pulse_sink_free(sink);
pulse_free(conn);
conn = NULL;
@ -265,6 +300,8 @@ e_mixer_pulse_get_cards(void)
EINA_LIST_FOREACH(sinks, l, sink)
ret = eina_list_append(ret, pulse_sink_name_get(sink));
EINA_LIST_FOREACH(sources, l, sink)
ret = eina_list_append(ret, pulse_sink_name_get(sink));
return ret;
}
@ -414,9 +451,9 @@ e_mixer_pulse_set_volume(E_Mixer_System *self, E_Mixer_Channel *channel, int lef
#ifdef BAD_CH_MAPPING
if (!channel) return 0;
id = pulse_sink_channel_volume_set(conn, (void *)self,
id = pulse_type_channel_volume_set(conn, (void *)self,
((uintptr_t)channel) - 1,
(left + right) / 2);
(left + right) / 2, source);
if (!id) return 0;
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
#else
@ -456,9 +493,11 @@ int
e_mixer_pulse_set_mute(E_Mixer_System *self, E_Mixer_Channel *channel __UNUSED__, int mute)
{
uint32_t idx, id;
Eina_Bool source = EINA_FALSE;
idx = pulse_sink_idx_get((void *)self);
id = pulse_sink_mute_set(conn, pulse_sink_idx_get((void *)self), mute);
source = !!eina_list_data_find(sources, self);
id = pulse_type_mute_set(conn, pulse_sink_idx_get((void *)self), mute, source);
if (!id) return 0;
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
return 1;
@ -489,10 +528,12 @@ e_mixer_pulse_set_state(E_Mixer_System *self, E_Mixer_Channel *channel, const E_
{
#ifdef BAD_CH_MAPPING
uint32_t id;
Eina_Bool source = EINA_FALSE;
if (!channel) return 0;
id = pulse_sink_channel_volume_set(conn, (void *)self,
source = !!eina_list_data_find(sources, self);
id = pulse_type_channel_volume_set(conn, (void *)self,
((uintptr_t)channel) - 1,
(state->left + state->right) / 2);
(state->left + state->right) / 2, source);
if (!id) return 0;
pulse_cb_set(conn, id, (Pulse_Cb)_pulse_result_cb);
#else